From f9465bf4d2a5c783b1bc88378983667b3b1465df Mon Sep 17 00:00:00 2001 From: Vlad S Date: Thu, 9 Feb 2023 14:39:26 +0000 Subject: [PATCH 01/12] UI: Selection on graph with edges. Status for jobs/datasets (#2384) * Selection on graph with edges. Status for jobs/datasets Signed-off-by: tito12 --------- Signed-off-by: tito12 Co-authored-by: Willy Lulciuc --- docker/metadata.json | 18 ++++- web/src/components/core/status/MqStatus.tsx | 41 ++++++++++ .../datasets/DatasetColumnLineage.tsx | 5 +- .../components/datasets/DatasetDetailPage.tsx | 22 ++++-- .../components/datasets/DatasetVersions.tsx | 5 +- web/src/components/jobs/JobDetailPage.tsx | 12 ++- web/src/components/jobs/RunStatus.tsx | 9 ++- web/src/components/lineage/Lineage.tsx | 57 +++++++++++--- .../lineage/components/drag-bar/DragBar.tsx | 5 +- .../lineage/components/edge/Edge.tsx | 42 +++++++++- .../lineage/components/node/Node.tsx | 76 ++++--------------- .../namespace-select/NamespaceSelect.tsx | 5 +- web/src/components/search/Search.tsx | 7 +- web/src/helpers/nodes.ts | 70 +++++++++++++++++ web/src/i18n/config.ts | 24 ++++-- web/src/routes/datasets/Datasets.tsx | 20 +++-- web/src/routes/events/Events.tsx | 38 ++-------- web/src/routes/jobs/Jobs.tsx | 17 +++-- web/src/types/api.ts | 14 +++- web/src/types/util/groupBy.ts | 5 +- 20 files changed, 329 insertions(+), 163 deletions(-) create mode 100644 web/src/components/core/status/MqStatus.tsx diff --git a/docker/metadata.json b/docker/metadata.json index 0b6c656cb6..65322f89cb 100644 --- a/docker/metadata.json +++ b/docker/metadata.json @@ -1358,6 +1358,22 @@ "_schemaURL": "https://openlineage.io/spec/facets/1-0-0/DatasourceDatasetFacet.json", "name": "food_delivery_db", "uri": "postgres://food_delivery:food_delivery@postgres:5432/food_delivery" + }, + "dataQualityAssertions": { + "_producer": "https://github.com/MarquezProject/marquez/blob/main/docker/metadata.json", + "_schemaURL": "https://openlineage.io/spec/facets/1-0-0/DataQualityAssertionsDatasetFacet.json", + "assertions": [ + { + "assertion": "not_null", + "success": false, + "column": "driver_id" + }, + { + "assertion": "is_string", + "success": true, + "column": "customer_address" + } + ] } } } @@ -1824,4 +1840,4 @@ }, "producer": "https://github.com/MarquezProject/marquez/blob/main/docker/metadata.json" } -] +] \ No newline at end of file diff --git a/web/src/components/core/status/MqStatus.tsx b/web/src/components/core/status/MqStatus.tsx new file mode 100644 index 0000000000..2c5f639614 --- /dev/null +++ b/web/src/components/core/status/MqStatus.tsx @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { theme } from '../../../helpers/theme' +import Box from '@material-ui/core/Box' +import MqText from '../text/MqText' +import React from 'react' +import createStyles from '@material-ui/core/styles/createStyles' +import withStyles, { WithStyles } from '@material-ui/core/styles/withStyles' + +const styles = () => + createStyles({ + type: { + display: 'flex', + alignItems: 'center', + gap: theme.spacing(1) + }, + status: { + width: theme.spacing(2), + height: theme.spacing(2), + borderRadius: '50%' + } + }) + +interface OwnProps { + color: string | null + label?: string +} + +const MqStatus: React.FC> = ({ label, color, classes }) => { + if (!color) { + return null + } + return ( + + + {label && {label}} + + ) +} + +export default withStyles(styles)(MqStatus) diff --git a/web/src/components/datasets/DatasetColumnLineage.tsx b/web/src/components/datasets/DatasetColumnLineage.tsx index b36b650122..ea7ce9d226 100644 --- a/web/src/components/datasets/DatasetColumnLineage.tsx +++ b/web/src/components/datasets/DatasetColumnLineage.tsx @@ -102,7 +102,4 @@ const mapDispatchToProps = (dispatch: Redux.Dispatch) => dispatch ) -export default connect( - mapStateToProps, - mapDispatchToProps -)(DatasetColumnLineage) +export default connect(mapStateToProps, mapDispatchToProps)(DatasetColumnLineage) diff --git a/web/src/components/datasets/DatasetDetailPage.tsx b/web/src/components/datasets/DatasetDetailPage.tsx index e366248f26..fe29690e2d 100644 --- a/web/src/components/datasets/DatasetDetailPage.tsx +++ b/web/src/components/datasets/DatasetDetailPage.tsx @@ -15,6 +15,7 @@ import { LineageDataset } from '../lineage/types' import { alpha } from '@material-ui/core/styles' import { bindActionCreators } from 'redux' import { connect } from 'react-redux' +import { datasetFacetsStatus } from '../../helpers/nodes' import { deleteDataset, dialogToggle, @@ -31,7 +32,9 @@ import DatasetInfo from './DatasetInfo' import DatasetVersions from './DatasetVersions' import Dialog from '../Dialog' import IconButton from '@material-ui/core/IconButton' +import MqStatus from '../core/status/MqStatus' import MqText from '../core/text/MqText' + import React, { ChangeEvent, FunctionComponent, SetStateAction, useEffect } from 'react' const styles = ({ spacing }: ITheme) => { @@ -143,6 +146,7 @@ const DatasetDetailPage: FunctionComponent = props => { const firstVersion = versions[0] const { name, tags, description } = firstVersion + const facetsStatus = datasetFacetsStatus(firstVersion.facets) return ( @@ -202,9 +206,16 @@ const DatasetDetailPage: FunctionComponent = props => { - - {name} - + + {facetsStatus && ( + + + + )} + + {name} + + {description} @@ -241,7 +252,4 @@ const mapDispatchToProps = (dispatch: Redux.Dispatch) => dispatch ) -export default connect( - mapStateToProps, - mapDispatchToProps -)(withStyles(styles)(DatasetDetailPage)) +export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(DatasetDetailPage)) diff --git a/web/src/components/datasets/DatasetVersions.tsx b/web/src/components/datasets/DatasetVersions.tsx index 9b8c9b3e48..db1b70b29a 100644 --- a/web/src/components/datasets/DatasetVersions.tsx +++ b/web/src/components/datasets/DatasetVersions.tsx @@ -31,9 +31,8 @@ interface DatasetVersionsProps { versions: DatasetVersion[] } -const DatasetVersions: FunctionComponent< - DatasetVersionsProps & IWithStyles -> = props => { +const DatasetVersions: FunctionComponent> = props => { const { versions, classes } = props const [infoView, setInfoView] = React.useState(null) diff --git a/web/src/components/jobs/JobDetailPage.tsx b/web/src/components/jobs/JobDetailPage.tsx index d4788dd62c..188d2b4d2d 100644 --- a/web/src/components/jobs/JobDetailPage.tsx +++ b/web/src/components/jobs/JobDetailPage.tsx @@ -25,15 +25,16 @@ import { resetJobs, resetRuns } from '../../store/actionCreators' +import { jobRunsStatus } from '../../helpers/nodes' import { theme } from '../../helpers/theme' import { useHistory } from 'react-router-dom' import CloseIcon from '@material-ui/icons/Close' import Dialog from '../Dialog' import IconButton from '@material-ui/core/IconButton' import MqEmpty from '../core/empty/MqEmpty' +import MqStatus from '../core/status/MqStatus' import MqText from '../core/text/MqText' import RunInfo from './RunInfo' -import RunStatus from './RunStatus' import Runs from './Runs' const styles = ({ spacing }: ITheme) => { @@ -166,9 +167,9 @@ const JobDetailPage: FunctionComponent = props => { - {job.latestRun && ( + {runs.length && ( - + )} @@ -212,7 +213,4 @@ const mapDispatchToProps = (dispatch: Redux.Dispatch) => dispatch ) -export default connect( - mapStateToProps, - mapDispatchToProps -)(withStyles(styles)(JobDetailPage)) +export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(JobDetailPage)) diff --git a/web/src/components/jobs/RunStatus.tsx b/web/src/components/jobs/RunStatus.tsx index 1695e16fe9..1b55b79d04 100644 --- a/web/src/components/jobs/RunStatus.tsx +++ b/web/src/components/jobs/RunStatus.tsx @@ -3,8 +3,7 @@ import { Box, Theme, Tooltip, WithStyles, createStyles, withStyles } from '@material-ui/core' import { Run } from '../../types/api' - -import { runColorMap } from '../../helpers/runs' +import { runStateColor } from '../../helpers/nodes' import React, { FunctionComponent } from 'react' @@ -26,7 +25,11 @@ const RunStatus: FunctionComponent> = const { run, classes } = props return ( - + ) } diff --git a/web/src/components/lineage/Lineage.tsx b/web/src/components/lineage/Lineage.tsx index 055f22572a..ed21deb8e1 100644 --- a/web/src/components/lineage/Lineage.tsx +++ b/web/src/components/lineage/Lineage.tsx @@ -85,6 +85,7 @@ class Lineage extends React.Component { const nodeName = this.props.match.params.nodeName const namespace = this.props.match.params.namespace const nodeType = this.props.match.params.nodeType + if (nodeName && namespace && nodeType) { const nodeId = generateNodeId( this.props.match.params.nodeType.toUpperCase() as JobOrDataset, @@ -114,6 +115,7 @@ class Lineage extends React.Component { this.props.match.params.namespace, this.props.match.params.nodeName ) + this.getEdges() } } @@ -129,6 +131,48 @@ class Lineage extends React.Component { }) } + getEdges = () => { + const selectedPaths = this.getSelectedPaths() + + return g?.edges().map(e => { + const isSelected = selectedPaths.some((r: any) => e.v === r[0] && e.w === r[1]) + return Object.assign(g.edge(e), { isSelected: isSelected }) + }) + } + + getSelectedPaths = () => { + const paths = [] as Array<[string, string]> + + const getSuccessors = (node: string) => { + const successors = g?.successors(node) + if (successors?.length) { + for (let i = 0; i < node.length - 1; i++) { + if (successors[i]) { + paths.push([node, (successors[i] as unknown) as string]) + getSuccessors((successors[i] as unknown) as string) + } + } + } + } + + const getPredecessors = (node: string) => { + const predecessors = g?.predecessors(node) + if (predecessors?.length) { + for (let i = 0; i < node.length - 1; i++) { + if (predecessors[i]) { + paths.push([(predecessors[i] as unknown) as string, node]) + getPredecessors((predecessors[i] as unknown) as string) + } + } + } + } + + getSuccessors(this.props.selectedNode) + getPredecessors(this.props.selectedNode) + + return paths + } + buildGraphAll = (graph: LineageNode[]) => { // nodes for (let i = 0; i < graph.length; i++) { @@ -150,7 +194,7 @@ class Lineage extends React.Component { this.setState({ graph: g, - edges: g.edges().map(e => g.edge(e)), + edges: this.getEdges(), nodes: g.nodes().map(v => g.node(v)) }) } @@ -158,6 +202,7 @@ class Lineage extends React.Component { render() { const { classes } = this.props const i18next = require('i18next') + return ( {this.props.selectedNode === null && ( @@ -227,9 +272,6 @@ class Lineage extends React.Component { edge.points[edge.points.length - 1] - )} selectedNode={this.props.selectedNode} /> ))} @@ -262,9 +304,4 @@ const mapDispatchToProps = (dispatch: Redux.Dispatch) => dispatch ) -export default withStyles(styles)( - connect( - mapStateToProps, - mapDispatchToProps - )(withRouter(Lineage)) -) +export default withStyles(styles)(connect(mapStateToProps, mapDispatchToProps)(withRouter(Lineage))) diff --git a/web/src/components/lineage/components/drag-bar/DragBar.tsx b/web/src/components/lineage/components/drag-bar/DragBar.tsx index f2e74f68ec..be57e8b8f9 100644 --- a/web/src/components/lineage/components/drag-bar/DragBar.tsx +++ b/web/src/components/lineage/components/drag-bar/DragBar.tsx @@ -107,7 +107,4 @@ const mapDispatchToProps = (dispatch: Redux.Dispatch) => }, dispatch ) -export default connect( - null, - mapDispatchToProps -)(withStyles(styles)(DragBar)) +export default connect(null, mapDispatchToProps)(withStyles(styles)(DragBar)) diff --git a/web/src/components/lineage/components/edge/Edge.tsx b/web/src/components/lineage/components/edge/Edge.tsx index 02c909da2b..cb5e3b3114 100644 --- a/web/src/components/lineage/components/edge/Edge.tsx +++ b/web/src/components/lineage/components/edge/Edge.tsx @@ -1,9 +1,11 @@ // Copyright 2018-2023 contributors to the Marquez project // SPDX-License-Identifier: Apache-2.0 +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { GraphEdge } from 'dagre' import { LinePath } from '@visx/shape' import { curveMonotoneX } from '@visx/curve' +import { faCaretRight } from '@fortawesome/free-solid-svg-icons/faCaretRight' import { theme } from '../../../../helpers/theme' import React from 'react' @@ -11,9 +13,36 @@ type EdgeProps = { edgePoints: GraphEdge[] } +type EdgePoint = { + isSelected: boolean + points: { + x: number + y: number + }[] +} + +const RADIUS = 14 +const OUTER_RADIUS = RADIUS + 8 +const ICON_SIZE = 16 + class Edge extends React.Component { + getPoints = (edge: EdgePoint) => edge.points[edge.points.length - 1] + render() { const { edgePoints } = this.props + const edgeEnds = edgePoints.map(edge => { + const isSelected = edgePoints.find( + o => + this.getPoints(o as EdgePoint).x == this.getPoints(edge as EdgePoint).x && + this.getPoints(o as EdgePoint).y == this.getPoints(edge as EdgePoint).y && + o.isSelected === true + ) + return { + ...edge.points[edge.points.length - 1], + ...{ isSelected: typeof isSelected !== 'undefined' } + } + }) + return ( <> {edgePoints.map((edge, i) => ( @@ -23,12 +52,23 @@ class Edge extends React.Component { data={edge.points} x={(d, index) => (index === 0 ? d.x + 20 : d.x - 25)} y={d => d.y} - stroke={theme.palette.secondary.main} + stroke={edge.isSelected ? theme.palette.common.white : theme.palette.secondary.main} strokeWidth={1} opacity={1} shapeRendering='geometricPrecision' /> ))} + {edgeEnds.map((edge, i) => ( + + ))} ) } diff --git a/web/src/components/lineage/components/node/Node.tsx b/web/src/components/lineage/components/node/Node.tsx index 890e3d6982..f76c3b494e 100644 --- a/web/src/components/lineage/components/node/Node.tsx +++ b/web/src/components/lineage/components/node/Node.tsx @@ -9,24 +9,16 @@ import { Node as GraphNode } from 'dagre' import { Link } from 'react-router-dom' import { MqNode } from '../../types' import { NodeText } from './NodeText' -import { Nullable } from '../../../../types/util/Nullable' -import { Run } from '../../../../types/api' import { bindActionCreators } from 'redux' + import { connect } from 'react-redux' import { encodeNode, isDataset, isJob } from '../../../../helpers/nodes' -import { faCaretRight } from '@fortawesome/free-solid-svg-icons/faCaretRight' import { faCog } from '@fortawesome/free-solid-svg-icons/faCog' import { faDatabase } from '@fortawesome/free-solid-svg-icons/faDatabase' import { setSelectedNode } from '../../../../store/actionCreators' import { theme } from '../../../../helpers/theme' -export type Vertex = { - x: number - y: number -} - const RADIUS = 14 -const OUTER_RADIUS = RADIUS + 8 const ICON_SIZE = 16 const BORDER = 4 @@ -36,29 +28,11 @@ interface DispatchProps { interface OwnProps { node: GraphNode - edgeEnds: Vertex[] selectedNode: string } type NodeProps = DispatchProps & OwnProps -function runStateToNodeColor(run: Nullable) { - switch (run && run.state) { - case 'NEW': - return theme.palette.secondary.main - case 'RUNNING': - return theme.palette.info.main - case 'COMPLETED': - return theme.palette.secondary.main - case 'FAILED': - return theme.palette.error.main - case 'ABORTED': - return theme.palette.warning.main - default: - return theme.palette.secondary.main - } -} - class Node extends React.Component { determineLink = (node: GraphNode) => { if (isJob(node)) { @@ -70,7 +44,7 @@ class Node extends React.Component { } render() { - const { node, edgeEnds, selectedNode } = this.props + const { node, selectedNode } = this.props const job = isJob(node) const isSelected = selectedNode === node.label const ariaJobLabel = 'Job' @@ -82,21 +56,14 @@ class Node extends React.Component { > {job ? ( + {/* { console.log(job.latestRun)} */} + {/* {console.log(runStateToNodeColor(job.latestRun))} */} - @@ -109,7 +76,7 @@ class Node extends React.Component { height={ICON_SIZE} x={node.x - ICON_SIZE / 2} y={node.y - ICON_SIZE / 2} - color={runStateToNodeColor(job.latestRun)} + color={isSelected ? theme.palette.common.white : theme.palette.secondary.main} /> ) : ( @@ -118,9 +85,9 @@ class Node extends React.Component { style={{ cursor: 'pointer' }} x={node.x - RADIUS} y={node.y - RADIUS} - fill={theme.palette.common.white} - stroke={isSelected ? theme.palette.primary.main : theme.palette.secondary.main} - strokeWidth={BORDER} + fill={isSelected ? theme.palette.secondary.main : theme.palette.common.white} + stroke={isSelected ? theme.palette.common.white : theme.palette.secondary.main} + strokeWidth={BORDER / 2} width={RADIUS * 2} height={RADIUS * 2} rx={4} @@ -129,9 +96,7 @@ class Node extends React.Component { style={{ cursor: 'pointer' }} x={node.x - (RADIUS - 2)} y={node.y - (RADIUS - 2)} - fill={theme.palette.common.white} - stroke={theme.palette.common.white} - strokeWidth={BORDER} + fill={isSelected ? theme.palette.secondary.main : theme.palette.common.white} width={(RADIUS - 2) * 2} height={(RADIUS - 2) * 2} rx={4} @@ -144,20 +109,10 @@ class Node extends React.Component { height={ICON_SIZE} x={node.x - ICON_SIZE / 2} y={node.y - ICON_SIZE / 2} - color={theme.palette.secondary.main} + color={isSelected ? theme.palette.common.white : theme.palette.secondary.main} /> )} - {edgeEnds.find(edge => edge.x === node.x && edge.y === node.y) && ( - - )} ) @@ -172,7 +127,4 @@ const mapDispatchToProps = (dispatch: Redux.Dispatch) => dispatch ) -export default connect( - null, - mapDispatchToProps -)(Node) +export default connect(null, mapDispatchToProps)(Node) diff --git a/web/src/components/namespace-select/NamespaceSelect.tsx b/web/src/components/namespace-select/NamespaceSelect.tsx index cf27735d5a..088430366c 100644 --- a/web/src/components/namespace-select/NamespaceSelect.tsx +++ b/web/src/components/namespace-select/NamespaceSelect.tsx @@ -84,7 +84,4 @@ const mapDispatchToProps = (dispatch: Redux.Dispatch) => dispatch ) -export default connect( - mapStateToProps, - mapDispatchToProps -)(withStyles(styles)(NamespaceSelect)) +export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(NamespaceSelect)) diff --git a/web/src/components/search/Search.tsx b/web/src/components/search/Search.tsx index 226e9eaaa4..8f4e1819e6 100644 --- a/web/src/components/search/Search.tsx +++ b/web/src/components/search/Search.tsx @@ -362,9 +362,4 @@ const mapDispatchToProps = (dispatch: Redux.Dispatch) => dispatch ) -export default withStyles(styles)( - connect( - mapStateToProps, - mapDispatchToProps - )(withRouter(Search)) -) +export default withStyles(styles)(connect(mapStateToProps, mapDispatchToProps)(withRouter(Search))) diff --git a/web/src/helpers/nodes.ts b/web/src/helpers/nodes.ts index 5c2ea2647c..1b4602f4d6 100644 --- a/web/src/helpers/nodes.ts +++ b/web/src/helpers/nodes.ts @@ -1,8 +1,10 @@ // Copyright 2018-2023 contributors to the Marquez project // SPDX-License-Identifier: Apache-2.0 +import { EventType, Facets, Run, RunState } from '../types/api' import { JobOrDataset, LineageDataset, LineageJob, MqNode } from '../components/lineage/types' import { Undefinable } from '../types/util/Nullable' +import { theme } from './theme' export function isJob(node: MqNode): Undefinable { if (node.data.type === 'BATCH') { @@ -56,3 +58,71 @@ type SearchDelimiterMap = typeof searchDelimiterMap export function parseSearchGroup(nodeId: string, field: keyof SearchDelimiterMap) { return nodeId.split(':')[searchDelimiterMap[field]] || '' } + +export function eventTypeColor(state: EventType) { + switch (state) { + case 'START': + return theme.palette.info.main + case 'RUNNING': + return theme.palette.info.main + case 'COMPLETE': + return theme.palette.primary.main + case 'FAIL': + return theme.palette.error.main + case 'ABORT': + return theme.palette.warning.main + default: + return theme.palette.secondary.main + } +} + +export function runStateColor(state: RunState) { + switch (state) { + case 'NEW': + return theme.palette.secondary.main + case 'RUNNING': + return theme.palette.info.main + case 'COMPLETED': + return theme.palette.primary.main + case 'FAILED': + return theme.palette.error.main + case 'ABORTED': + return theme.palette.warning.main + default: + return theme.palette.secondary.main + } +} + +export function jobRunsStatus(runs: Run[], limit = 14) { + runs = runs.slice(-limit) + + const isAllFailed = runs.every(e => e.state === 'FAILED') + const isSomeFailed = runs.some(e => e.state === 'FAILED') + + if (isAllFailed) { + return theme.palette.error.main as string + } else if (isSomeFailed) { + return theme.palette.info.main as string + } else { + return theme.palette.primary.main as string + } +} + +export function datasetFacetsStatus(facets: Facets, limit = 14) { + const assertions = facets?.dataQualityAssertions?.assertions?.slice(-limit) + + if (!assertions?.length) { + return null + } + + const isAllFalse = assertions.every((e: any) => e.success === false) + const isSomeFalse = assertions.some((e: any) => e.success === false) + + if (isAllFalse) { + return theme.palette.error.main as string + } else if (isSomeFalse) { + return theme.palette.info.main as string + } else { + return theme.palette.primary.main as string + } +} diff --git a/web/src/i18n/config.ts b/web/src/i18n/config.ts index 96d4adee68..6a9b48c3a4 100644 --- a/web/src/i18n/config.ts +++ b/web/src/i18n/config.ts @@ -75,7 +75,8 @@ i18next name_col: 'NAME', namespace_col: 'NAMESPACE', source_col: 'SOURCE', - updated_col: 'UPDATED AT' + updated_col: 'UPDATED AT', + status_col: 'STATUS' }, datasets_column_lineage: { empty_title: 'No column lineage', @@ -88,7 +89,8 @@ i18next name_col: 'NAME', namespace_col: 'NAMESPACE', updated_col: 'UPDATED AT', - latest_run_col: 'LATEST RUN DURATION' + latest_run_col: 'LATEST RUN DURATION', + latest_run_state_col: 'LATEST RUN STATE' }, runs_columns: { id: 'ID', @@ -185,7 +187,8 @@ i18next name_col: 'NOM', namespace_col: 'ESPACE DE NOMS', source_col: 'SOURCE', - updated_col: 'MISE À JOUR À' + updated_col: 'MISE À JOUR À', + status_col: 'STATUT' }, datasets_column_lineage: { empty_title: 'Aucune lignée de colonne', @@ -199,7 +202,8 @@ i18next name_col: 'NOM', namespace_col: 'ESPACE DE NOMS', updated_col: 'MISE À JOUR À', - latest_run_col: "DERNIÈRE DURÉE D'EXÉCUTION" + latest_run_col: "DERNIÈRE DURÉE D'EXÉCUTION", + latest_run_state_col: "DERNIER ÉTAT D'EXÉCUTIONE" }, runs_columns: { id: 'ID', @@ -297,7 +301,8 @@ i18next name_col: 'NOMBRE', namespace_col: 'ESPACIO DE NOMBRES', source_col: 'FUENTE', - updated_col: 'ACTUALIZADO EN' + updated_col: 'ACTUALIZADO EN', + status_col: 'ESTADO' }, datasets_column_lineage: { empty_title: 'Sin linaje de columna', @@ -311,7 +316,8 @@ i18next name_col: 'NOMBRE', namespace_col: 'ESPACIO DE NOMBRES', updated_col: 'ACTUALIZADO EN', - latest_run_col: 'DURACIÓN DE LA ÚLTIMA EJECUCIÓN' + latest_run_col: 'DURACIÓN DE LA ÚLTIMA EJECUCIÓN', + latest_run_state_col: 'ESTADO DE LA ÚLTIMA EJECUCIÓN' }, runs_columns: { id: 'ID', @@ -409,7 +415,8 @@ i18next name_col: 'NAZWA', namespace_col: 'PRZESTRZEŃ NAZW', source_col: 'ŹRÓDŁO', - updated_col: 'ZAKTUALIZOWANO' + updated_col: 'ZAKTUALIZOWANO', + status_col: 'STATUS' }, datasets_column_lineage: { empty_title: 'Brak rodowodu kolumny', @@ -423,7 +430,8 @@ i18next name_col: 'NAZWA', namespace_col: 'PRZESTRZEŃ NAZW', updated_col: 'ZAKTUALIZOWANO', - latest_run_col: 'NAJNOWSZY CZAS TRWANIA' + latest_run_col: 'NAJNOWSZY CZAS TRWANIA', + latest_run_state_col: 'NAJNOWSZY STAN URUCHOMIENIA' }, runs_columns: { id: 'ID', diff --git a/web/src/routes/datasets/Datasets.tsx b/web/src/routes/datasets/Datasets.tsx index d93773b527..97ca472508 100644 --- a/web/src/routes/datasets/Datasets.tsx +++ b/web/src/routes/datasets/Datasets.tsx @@ -9,11 +9,12 @@ import { MqScreenLoad } from '../../components/core/screen-load/MqScreenLoad' import { Nullable } from '../../types/util/Nullable' import { bindActionCreators } from 'redux' import { connect } from 'react-redux' -import { encodeNode } from '../../helpers/nodes' +import { datasetFacetsStatus, encodeNode } from '../../helpers/nodes' import { fetchDatasets, resetDatasets } from '../../store/actionCreators' import { formatUpdatedAt } from '../../helpers' import Box from '@material-ui/core/Box' import MqEmpty from '../../components/core/empty/MqEmpty' +import MqStatus from '../../components/core/status/MqStatus' import MqText from '../../components/core/text/MqText' import React from 'react' import createStyles from '@material-ui/core/styles/createStyles' @@ -88,6 +89,9 @@ class Datasets extends React.Component { {i18next.t('datasets_route.updated_col')} + + {i18next.t('datasets_route.status_col')} + @@ -117,6 +121,15 @@ class Datasets extends React.Component { {formatUpdatedAt(dataset.updatedAt)} + + {datasetFacetsStatus(dataset.facets) ? ( + <> + + + ) : ( + N/A + )} + ) })} @@ -147,7 +160,4 @@ const mapDispatchToProps = (dispatch: Redux.Dispatch) => dispatch ) -export default connect( - mapStateToProps, - mapDispatchToProps -)(withStyles(styles)(Datasets)) +export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(Datasets)) diff --git a/web/src/routes/events/Events.tsx b/web/src/routes/events/Events.tsx index 678dbe9155..d18da28b35 100644 --- a/web/src/routes/events/Events.tsx +++ b/web/src/routes/events/Events.tsx @@ -19,16 +19,17 @@ import { IState } from '../../store/reducers' import { MqScreenLoad } from '../../components/core/screen-load/MqScreenLoad' import { bindActionCreators } from 'redux' import { connect } from 'react-redux' +import { eventTypeColor } from '../../helpers/nodes' import { fetchEvents, resetEvents } from '../../store/actionCreators' import { fileSize, formatUpdatedAt } from '../../helpers' import { formatDateAPIQuery, formatDatePicker } from '../../helpers/time' import { saveAs } from 'file-saver' -import { theme } from '../../helpers/theme' import Box from '@material-ui/core/Box' import IconButton from '@material-ui/core/IconButton' import MqDatePicker from '../../components/core/date-picker/MqDatePicker' import MqEmpty from '../../components/core/empty/MqEmpty' import MqJson from '../../components/core/code/MqJson' +import MqStatus from '../../components/core/status/MqStatus' import MqText from '../../components/core/text/MqText' import React from 'react' import createStyles from '@material-ui/core/styles/createStyles' @@ -42,16 +43,6 @@ const styles = (theme: Theme) => { alignItems: 'center', gap: theme.spacing(2) }, - type: { - display: 'flex', - alignItems: 'center', - gap: theme.spacing(1) - }, - status: { - width: theme.spacing(2), - height: theme.spacing(2), - borderRadius: '50%' - }, table: { marginBottom: theme.spacing(2) }, @@ -91,15 +82,6 @@ type EventsProps = WithStyles & StateProps & DispatchProps const EVENTS_COLUMNS = ['ID', 'STATE', 'NAME', 'NAMESPACE', 'TIME'] -function eventTypeColor(type: string) { - switch (type) { - case 'START': - return theme.palette.info.main - case 'COMPLETE': - return theme.palette.primary.main - } -} - class Events extends React.Component { pageSize: number @@ -284,13 +266,10 @@ class Events extends React.Component { {event.run.runId} - - - {event.eventType} - + {event.job.name} @@ -381,7 +360,4 @@ const mapDispatchToProps = (dispatch: Redux.Dispatch) => dispatch ) -export default connect( - mapStateToProps, - mapDispatchToProps -)(withStyles(styles)(Events)) +export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(Events)) diff --git a/web/src/routes/jobs/Jobs.tsx b/web/src/routes/jobs/Jobs.tsx index ab61eb848e..74704d3bab 100644 --- a/web/src/routes/jobs/Jobs.tsx +++ b/web/src/routes/jobs/Jobs.tsx @@ -9,12 +9,13 @@ import { MqScreenLoad } from '../../components/core/screen-load/MqScreenLoad' import { Nullable } from '../../types/util/Nullable' import { bindActionCreators } from 'redux' import { connect } from 'react-redux' -import { encodeNode } from '../../helpers/nodes' +import { encodeNode, runStateColor } from '../../helpers/nodes' import { fetchJobs, resetJobs } from '../../store/actionCreators' import { formatUpdatedAt } from '../../helpers' import { stopWatchDuration } from '../../helpers/time' import Box from '@material-ui/core/Box' import MqEmpty from '../../components/core/empty/MqEmpty' +import MqStatus from '../../components/core/status/MqStatus' import MqText from '../../components/core/text/MqText' import React from 'react' @@ -85,6 +86,9 @@ class Jobs extends React.Component { {i18next.t('jobs_route.latest_run_col')} + + {i18next.t('jobs_route.latest_run_state_col')} + @@ -112,6 +116,12 @@ class Jobs extends React.Component { : 'N/A'} + + + ) })} @@ -142,7 +152,4 @@ const mapDispatchToProps = (dispatch: Redux.Dispatch) => dispatch ) -export default connect( - mapStateToProps, - mapDispatchToProps -)(Jobs) +export default connect(mapStateToProps, mapDispatchToProps)(Jobs) diff --git a/web/src/types/api.ts b/web/src/types/api.ts index d223473c34..04d939af4e 100644 --- a/web/src/types/api.ts +++ b/web/src/types/api.ts @@ -28,8 +28,10 @@ export interface Events { events: Event[] } +export type EventType = 'START' | 'RUNNING' | 'ABORT' | 'FAIL' | 'COMPLETE' + export interface Event { - eventType: string + eventType: EventType eventTime: string producer: string schemaURL: string @@ -80,6 +82,16 @@ export interface DatasetVersions { versions: DatasetVersion[] } +export interface Facets { + dataQualityAssertions?: { + assertions?: { + assertion: string + column: string + success: boolean + }[] + } +} + export interface DatasetVersion { id: DatasetVersionId type: DatasetType diff --git a/web/src/types/util/groupBy.ts b/web/src/types/util/groupBy.ts index 4d9ee1aa59..d114c0c562 100644 --- a/web/src/types/util/groupBy.ts +++ b/web/src/types/util/groupBy.ts @@ -6,7 +6,10 @@ export function groupBy(list: T[], key: K) { list.forEach(item => { const itemKey = item[key] if (!map.has(itemKey)) { - map.set(itemKey, list.filter(i => i[key] === item[key])) + map.set( + itemKey, + list.filter(i => i[key] === item[key]) + ) } }) return map From f260382c5e05e3476a4714410596f687c896a00f Mon Sep 17 00:00:00 2001 From: Michael Collado <40346148+collado-mike@users.noreply.github.com> Date: Thu, 9 Feb 2023 07:38:01 -0800 Subject: [PATCH 02/12] Add index on jobs_fqn namespace and fqn to optimize read queries (#2357) Signed-off-by: Michael Collado --- .../resources/marquez/db/migration/V58__job_fqn_name_index.sql | 1 + 1 file changed, 1 insertion(+) create mode 100644 api/src/main/resources/marquez/db/migration/V58__job_fqn_name_index.sql diff --git a/api/src/main/resources/marquez/db/migration/V58__job_fqn_name_index.sql b/api/src/main/resources/marquez/db/migration/V58__job_fqn_name_index.sql new file mode 100644 index 0000000000..ed03171a62 --- /dev/null +++ b/api/src/main/resources/marquez/db/migration/V58__job_fqn_name_index.sql @@ -0,0 +1 @@ +CREATE INDEX ON jobs_fqn (namespace_name, job_fqn); \ No newline at end of file From 9a79bb72b11c3acdea69d40760425b290c0bea08 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 9 Feb 2023 09:18:29 -0800 Subject: [PATCH 03/12] fix(deps): update dependency org.postgresql:postgresql to v42.5.3 (#2401) Signed-off-by: Renovate Bot Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index fb0347c907..129e1304dc 100644 --- a/build.gradle +++ b/build.gradle @@ -62,7 +62,7 @@ subprojects { mockitoVersion = '5.1.0' openlineageVersion = '0.19.2' slf4jVersion = '1.7.36' - postgresqlVersion = '42.5.1' + postgresqlVersion = '42.5.3' isReleaseVersion = !version.endsWith('SNAPSHOT') } From 8ad564efa9bbf9a384a1d286aa7bbff5b65027e4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 9 Feb 2023 09:18:59 -0800 Subject: [PATCH 04/12] fix(deps): update dependency com.diffplug.spotless:spotless-plugin-gradle to v6.14.1 (#2405) Signed-off-by: Renovate Bot Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 129e1304dc..e4607e06b6 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ buildscript { dependencies { classpath 'com.adarshr:gradle-test-logger-plugin:3.2.0' classpath 'gradle.plugin.com.github.johnrengelman:shadow:7.1.2' - classpath 'com.diffplug.spotless:spotless-plugin-gradle:6.14.0' + classpath 'com.diffplug.spotless:spotless-plugin-gradle:6.14.1' } } From 2d8996bd9e24a34f4501f7c96a2e47597a472a7f Mon Sep 17 00:00:00 2001 From: Willy Lulciuc Date: Thu, 9 Feb 2023 09:26:49 -0800 Subject: [PATCH 05/12] `patch` -> `minor` (#2413) Signed-off-by: wslulciuc --- renovate.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index 6f58329397..ab7744687d 100644 --- a/renovate.json +++ b/renovate.json @@ -1,5 +1,5 @@ { - "bumpVersion": "patch", + "bumpVersion": "minor", "extends": [ "config:base", "docker:disable", From 89b9cd80bdcec734d93677d416fe2335232d50a2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 9 Feb 2023 09:57:01 -0800 Subject: [PATCH 06/12] fix(deps): update jdbi3version to v3.37.1 (#2404) Signed-off-by: Renovate Bot Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Willy Lulciuc --- api/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/build.gradle b/api/build.gradle index 2322285cf8..2ae7458418 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -21,7 +21,7 @@ plugins { } ext { - jdbi3Version = '3.36.0' + jdbi3Version = '3.37.1' prometheusVersion = '0.16.0' testcontainersVersion = '1.17.6' sentryVersion = '6.13.0' From 9a3936a1fd18fa439debc74dfb619f5f06405f87 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 9 Feb 2023 09:57:19 -0800 Subject: [PATCH 07/12] fix(deps): update mockito monorepo to v5.1.1 (#2403) Signed-off-by: Renovate Bot Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e4607e06b6..fa3eaa01c2 100644 --- a/build.gradle +++ b/build.gradle @@ -59,7 +59,7 @@ subprojects { jacocoVersion = '0.8.8' junit5Version = '5.9.2' lombokVersion = '1.18.24' - mockitoVersion = '5.1.0' + mockitoVersion = '5.1.1' openlineageVersion = '0.19.2' slf4jVersion = '1.7.36' postgresqlVersion = '42.5.3' From e7fbd813456c568b855f99657d6ae43dc25713e9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 9 Feb 2023 10:11:45 -0800 Subject: [PATCH 08/12] fix(deps): update dependency org.projectlombok:lombok to v1.18.26 (#2402) Signed-off-by: Renovate Bot Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Willy Lulciuc --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index fa3eaa01c2..d7158323dc 100644 --- a/build.gradle +++ b/build.gradle @@ -58,7 +58,7 @@ subprojects { dropwizardVersion = '2.1.4' jacocoVersion = '0.8.8' junit5Version = '5.9.2' - lombokVersion = '1.18.24' + lombokVersion = '1.18.26' mockitoVersion = '5.1.1' openlineageVersion = '0.19.2' slf4jVersion = '1.7.36' From b86d126ae8928964a7bf534231c807aef19857f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Feb 2023 10:33:44 -0800 Subject: [PATCH 09/12] Bump json5 from 1.0.1 to 1.0.2 in /web (#2349) Bumps [json5](https://github.com/json5/json5) from 1.0.1 to 1.0.2. - [Release notes](https://github.com/json5/json5/releases) - [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md) - [Commits](https://github.com/json5/json5/compare/v1.0.1...v1.0.2) --- updated-dependencies: - dependency-name: json5 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Willy Lulciuc --- web/package-lock.json | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 5f6f637b8a..f234c31d4a 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -11038,9 +11038,9 @@ "dev": true }, "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "bin": { "json5": "lib/cli.js" @@ -11217,9 +11217,9 @@ } }, "node_modules/loader-utils/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dependencies": { "minimist": "^1.2.0" }, @@ -24675,9 +24675,9 @@ "dev": true }, "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true }, "jss": { @@ -24825,9 +24825,9 @@ }, "dependencies": { "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "requires": { "minimist": "^1.2.0" } From 388eb3f4fad8cb1cdc522eedf981ea5d282756f5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 Feb 2023 09:46:53 -0800 Subject: [PATCH 10/12] fix(deps): update dependency io.openlineage:openlineage-java to v0.20.6 (#2416) Signed-off-by: Renovate Bot Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d7158323dc..00315ab71e 100644 --- a/build.gradle +++ b/build.gradle @@ -60,7 +60,7 @@ subprojects { junit5Version = '5.9.2' lombokVersion = '1.18.26' mockitoVersion = '5.1.1' - openlineageVersion = '0.19.2' + openlineageVersion = '0.20.6' slf4jVersion = '1.7.36' postgresqlVersion = '42.5.3' isReleaseVersion = !version.endsWith('SNAPSHOT') From aa1cfcea3b6561e111469109d891b669c6cce5fb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 Feb 2023 18:57:07 +0100 Subject: [PATCH 11/12] fix(deps): update dependency com.diffplug.spotless:spotless-plugin-gradle to v6.15.0 (#2415) Signed-off-by: Renovate Bot Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 00315ab71e..9520c36e9e 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ buildscript { dependencies { classpath 'com.adarshr:gradle-test-logger-plugin:3.2.0' classpath 'gradle.plugin.com.github.johnrengelman:shadow:7.1.2' - classpath 'com.diffplug.spotless:spotless-plugin-gradle:6.14.1' + classpath 'com.diffplug.spotless:spotless-plugin-gradle:6.15.0' } } From 0e434d5b91a615d548f1805cd2ae9d22ea35e515 Mon Sep 17 00:00:00 2001 From: "pawel.leszczynski" Date: Tue, 14 Feb 2023 17:48:47 +0100 Subject: [PATCH 12/12] include missing indexes (#2419) Signed-off-by: Pawel Leszczynski --- CHANGELOG.md | 6 ++++++ .../V59.1__column_lineage_add_indexes.sql | 11 +++++++++++ .../db/migration/V59.2__facet_tables_indexes.sql | 14 ++++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 api/src/main/resources/marquez/db/migration/V59.1__column_lineage_add_indexes.sql create mode 100644 api/src/main/resources/marquez/db/migration/V59.2__facet_tables_indexes.sql diff --git a/CHANGELOG.md b/CHANGELOG.md index 30199f2e0f..a937bd9672 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## [Unreleased](https://github.com/MarquezProject/marquez/compare/0.30.0...HEAD) +### Fixed + +* Add missing database indexes [`#2419`](https://github.com/MarquezProject/marquez/pull/2419) [@pawel-big-lebowski](https://github.com/pawel-big-lebowski) + *Create missing indexes on reference columns.* + + ## [0.30.0](https://github.com/MarquezProject/marquez/compare/0.29.0...0.30.0) - 2023-01-31 ### Added diff --git a/api/src/main/resources/marquez/db/migration/V59.1__column_lineage_add_indexes.sql b/api/src/main/resources/marquez/db/migration/V59.1__column_lineage_add_indexes.sql new file mode 100644 index 0000000000..29f294b551 --- /dev/null +++ b/api/src/main/resources/marquez/db/migration/V59.1__column_lineage_add_indexes.sql @@ -0,0 +1,11 @@ +create index column_lineage_output_dataset_version_uuid_index + on column_lineage (output_dataset_version_uuid); + +create index column_lineage_output_dataset_field_uuid_index + on column_lineage (output_dataset_field_uuid); + +create index column_lineage_input_dataset_version_uuid_index + on column_lineage (input_dataset_version_uuid); + +create index column_lineage_input_dataset_field_uuid_index + on column_lineage (input_dataset_field_uuid); \ No newline at end of file diff --git a/api/src/main/resources/marquez/db/migration/V59.2__facet_tables_indexes.sql b/api/src/main/resources/marquez/db/migration/V59.2__facet_tables_indexes.sql new file mode 100644 index 0000000000..3fb183e743 --- /dev/null +++ b/api/src/main/resources/marquez/db/migration/V59.2__facet_tables_indexes.sql @@ -0,0 +1,14 @@ +create index dataset_facets_dataset_uuid_index + on dataset_facets (dataset_uuid); + +create index dataset_facets_dataset_version_uuid_index + on dataset_facets (dataset_version_uuid); + +create index dataset_facets_run_uuid_index + on dataset_facets (run_uuid); + +create index job_facets_job_uuid_index + on job_facets (job_uuid); + +create index job_facets_run_uuid_index + on job_facets (run_uuid); \ No newline at end of file