@@ -68,7 +68,6 @@ public LineageService(LineageDao delegate, JobDao jobDao, RunDao runDao) {
6868 // TODO make input parameters easily extendable if adding more options like
6969 // 'withJobFacets'
7070 public Lineage lineage (NodeId nodeId , int depth ) {
71- log .debug ("Attempting to get lineage for node '{}' with depth '{}'" , nodeId .getValue (), depth );
7271 Optional <UUID > optionalUUID = getJobUuid (nodeId );
7372 if (optionalUUID .isEmpty ()) {
7473 log .warn (
@@ -77,7 +76,6 @@ public Lineage lineage(NodeId nodeId, int depth) {
7776 return toLineageWithOrphanDataset (nodeId .asDatasetId ());
7877 }
7978 UUID job = optionalUUID .get ();
80- log .debug ("Attempting to get lineage for job '{}'" , job );
8179 Set <JobData > jobData = getLineage (Collections .singleton (job ), depth );
8280
8381 // Ensure job data is not empty, an empty set cannot be passed to
@@ -310,11 +308,10 @@ public UpstreamRunLineage upstream(@NotNull RunId runId, int depth) {
310308 */
311309 public Lineage directLineage (NodeId nodeId , int depth ) {
312310 depth += 1 ;
313- log .debug ("Attempting to get lineage for node '{}' with depth '{}'" , nodeId .getValue (), depth );
314311 Optional <UUID > optionalUUID = getJobUuid (nodeId );
315312 if (optionalUUID .isEmpty ()) {
316- log .warn ("Failed to get job for node '{}', returning orphan dataset..." , nodeId .getValue ());
317- return toLineageWithOrphanDataset (nodeId .asDatasetId ());
313+ log .warn ("Failed to get job for node '{}', returning orphan dataset..." , nodeId .getValue ());
314+ return toLineageWithOrphanDataset (nodeId .asDatasetId ());
318315 }
319316 UUID job = optionalUUID .get ();
320317
@@ -324,61 +321,64 @@ public Lineage directLineage(NodeId nodeId, int depth) {
324321 Set <JobData > allJobData = new HashSet <>();
325322
326323 for (int level = 0 ; level < depth && !pending .isEmpty (); level ++) {
327- // Step 1: fetch direct lineage for the current pending job set
328- Set <JobData > directLineage = getDirectLineage (pending );
329- allJobData .addAll (directLineage );
330-
331- // Collect all job UUIDs we discover this iteration
332- Set <UUID > nextJobs = new HashSet <>();
333- visited .addAll (pending );
334- pending .clear ();
335-
336- // Step 2: for each job in current iteration:
337- for (JobData jd : directLineage ) {
338- // Step 2a: gather any dataset inputs/outputs
339- Set <UUID > dsUuids = new HashSet <>();
340- dsUuids .addAll (jd .getInputUuids ());
341- dsUuids .addAll (jd .getOutputUuids ());
342-
343- // Fetch all dataset info once
344- Set <DatasetData > dsList = getDatasetData (dsUuids );
345-
346- // Step 2b: for each dataset, find the job(s) associated with it
347- for (UUID dsUuid : dsUuids ) {
348- DatasetData ds = dsList .stream ()
349- .filter (d -> d .getUuid ().equals (dsUuid ))
350- .findFirst ()
351- .orElse (null );
352- if (ds == null ) {
353- continue ;
354- }
355- // Only follow upstream/downstream direction based on whether the dataset
356- // is an input or output
357- if (jd .getInputUuids ().contains (dsUuid )) {
358- // IMPORTANT: Use the string values
359- Optional <UUID > maybeJob = getJobFromInputOrOutput (
360- ds .getName ().getValue (),
361- ds .getNamespace ().getValue ());
362- maybeJob .ifPresent (nextJobs ::add );
363- }
324+ // Step 1: fetch direct lineage for the current pending job set
325+ Set <JobData > directLineage = getDirectLineage (pending );
326+ allJobData .addAll (directLineage );
327+
328+ // Collect all job UUIDs we discover this iteration
329+ Set <UUID > nextJobs = new HashSet <>();
330+ visited .addAll (pending );
331+ pending .clear ();
332+
333+ // Step 2: for each job in current iteration:
334+ for (JobData jd : directLineage ) {
335+ // Step 2a: gather any dataset inputs/outputs
336+ Set <UUID > dsUuids = new HashSet <>();
337+ dsUuids .addAll (jd .getInputUuids ());
338+ dsUuids .addAll (jd .getOutputUuids ());
339+
340+ // Fetch all dataset info once
341+ Set <DatasetData > dsList = getDatasetData (dsUuids );
342+
343+ // Step 2b: for each dataset, find the job(s) associated with it
344+ for (UUID dsUuid : dsUuids ) {
345+ DatasetData ds = dsList .stream ()
346+ .filter (d -> d .getUuid ().equals (dsUuid ))
347+ .findFirst ()
348+ .orElse (null );
349+ if (ds == null ) {
350+ continue ;
351+ }
352+
353+ // Follow upstream (jobs producing this dataset)
354+ if (jd .getInputUuids ().contains (dsUuid )) {
355+ Set <UUID > upstreamJobs = getUpstreamJobs (ds );
356+ nextJobs .addAll (upstreamJobs );
357+ }
358+
359+ // Follow downstream (jobs consuming this dataset)
360+ if (jd .getOutputUuids ().contains (dsUuid )) {
361+ Set <UUID > downstreamJobs = getDownstreamJobs (ds );
362+ nextJobs .addAll (downstreamJobs );
363+ }
364+ }
364365 }
365- }
366366
367- // Step 3: remove visited jobs
368- nextJobs .removeAll (visited );
367+ // Step 3: remove visited jobs
368+ nextJobs .removeAll (visited );
369369
370- // Step 4: pending becomes nextJobs
371- pending .addAll (nextJobs );
370+ // Step 4: pending becomes nextJobs
371+ pending .addAll (nextJobs );
372372 }
373373
374374 if (allJobData .isEmpty ()) {
375- log .warn ("No lineage for job '{}' node '{}', returning orphan dataset..." , job , nodeId .getValue ());
376- return toLineageWithOrphanDataset (nodeId .asDatasetId ());
375+ log .warn ("No lineage for job '{}' node '{}', returning orphan dataset..." , job , nodeId .getValue ());
376+ return toLineageWithOrphanDataset (nodeId .asDatasetId ());
377377 }
378378
379379 // Enrich with run data
380380 for (JobData j : allJobData ) {
381- runDao .findRunByUuid (j .getCurrentRunUuid ()).ifPresent (j ::setLatestRun );
381+ runDao .findRunByUuid (j .getCurrentRunUuid ()).ifPresent (j ::setLatestRun );
382382 }
383383
384384 // Retrieve all datasets from the discovered lineage
@@ -389,21 +389,38 @@ public Lineage directLineage(NodeId nodeId, int depth) {
389389 ? new HashSet <>()
390390 : getDatasetData (datasetIds );
391391
392- // If this started at a dataset node, ensure it’ s included in the final lineage
392+ // If this started at a dataset node, ensure it' s included in the final lineage
393393 if (nodeId .isDatasetType ()) {
394- DatasetId datasetId = nodeId .asDatasetId ();
395- DatasetData datasetData = getDatasetData (
396- datasetId .getNamespace ().getValue (),
397- datasetId .getName ().getValue ());
398- if (!datasetIds .contains (datasetData .getUuid ())) {
399- log .warn ("Found jobs with no lineage for dataset '{}', discarding" , nodeId .getValue ());
400- return toLineageWithOrphanDataset (datasetId );
401- }
394+ DatasetId datasetId = nodeId .asDatasetId ();
395+ DatasetData datasetData = getDatasetData (
396+ datasetId .getNamespace ().getValue (),
397+ datasetId .getName ().getValue ());
398+ if (!datasetIds .contains (datasetData .getUuid ())) {
399+ log .warn ("Found jobs with no lineage for dataset '{}', discarding" , nodeId .getValue ());
400+ return toLineageWithOrphanDataset (datasetId );
401+ }
402402 }
403403
404+
405+
404406 return toLineage (allJobData , datasets );
405407 }
406408
409+ private Set <UUID > getUpstreamJobs (DatasetData dataset ) {
410+ return delegate .getJobFromInputOrOutput (
411+ dataset .getName ().getValue (),
412+ dataset .getNamespace ().getValue ()
413+ ).map (Collections ::singleton )
414+ .orElse (Collections .emptySet ());
415+ }
416+
417+ private Set <UUID > getDownstreamJobs (DatasetData dataset ) {
418+ return delegate .getDownstreamJobs (
419+ dataset .getNamespace ().getValue (),
420+ dataset .getName ().getValue ()
421+ );
422+ }
423+
407424 /**
408425 * Fetch dataset information for the given set of dataset UUIDs.
409426 */
0 commit comments