1+ // Path Finding - Longest path - Stream - List all dependencies for nodes contributing to longest paths and highlight those paths in the Visualization with GraphViz.
2+
3+ // Gather global statistics about dependency weights and levels for normalization and node details
4+ MATCH (sourceNodeForStatistics )- [ dependencyForStatistics : DEPENDS_ON ] -> (targetNodeForStatistics )
5+ WHERE $dependencies_projection_node IN LABELS (sourceNodeForStatistics )
6+ AND $dependencies_projection_node IN LABELS (targetNodeForStatistics )
7+ WITH min (dependencyForStatistics [$dependencies_projection_weight_property ]) AS minWeight
8+ ,max (dependencyForStatistics [$dependencies_projection_weight_property ]) AS maxWeight
9+ ,max (targetNodeForStatistics .maxDistanceFromSource ) AS maxLevel
10+ WITH * , 1.0 / toFloat (maxWeight - minWeight ) AS weightNormalizationFactor
11+ WITH { minWeight : minWeight , maxLevel : maxLevel , weightNormalizationFactor : weightNormalizationFactor } AS statistics
12+ // -> Main call to execute "longest path" algorithm
13+ CALL gds .dag .longestPath .stream ($dependencies_projection + '-cleaned' )
14+ YIELD index , totalCost , path
15+ WITH *
16+ // Sort longest paths by their length descending and - if equal - by their index ascending
17+ ORDER BY totalCost DESC , index ASC
18+ // Collect all results of the longest path search as well as all nodes of the longest paths
19+ WITH statistics
20+ ,collect ({ index : index , distance : toInteger (totalCost ), path : path } ) AS longestPaths
21+ ,collect (nodes (path )) AS allLongestPathNodes
22+ // Flatten and deduplicate the list of all nodes that contribute to at least one longest path
23+ UNWIND allLongestPathNodes AS longestPathNodes
24+ UNWIND longestPathNodes AS longestPathNode
25+ WITH statistics
26+ ,longestPaths
27+ ,collect (DISTINCT longestPathNode ) AS allDistinctLongestPathNodes
28+ // Iterate over all longest paths
29+ UNWIND longestPaths AS longestPath
30+ WITH statistics
31+ ,longestPaths , allDistinctLongestPathNodes
32+ ,[ singleRelationship IN relationships (longestPath .path ) | [startNode (singleRelationship ), endNode (singleRelationship )] ] AS allLongestPathStartAndEndNodeTuples
33+ ,[ singleRelationship IN relationships (longestPaths [0 ].path ) | [startNode (singleRelationship ), endNode (singleRelationship )] ] AS longestPathStartAndEndNodeTuples
34+ ,longestPath .index AS index
35+ ,longestPath .distance AS distance
36+ // -> Main query of all dependencies of nodes contributing to the longest paths
37+ MATCH (source )- [ dependency : DEPENDS_ON ] -> (target )
38+ WHERE $dependencies_projection_node IN labels (source )
39+ AND $dependencies_projection_node IN labels (target )
40+ // Dependent nodes need to be part of at least one longest paths
41+ AND (source IN allDistinctLongestPathNodes AND target IN allDistinctLongestPathNodes )
42+ WITH statistics .maxLevel AS maxLevel
43+ ,statistics .minWeight AS minWeight
44+ ,statistics .weightNormalizationFactor AS weightNormalizationFactor
45+ ,count (index ) AS numberOfLongestPathsPassing
46+ ,max (distance ) AS lengthOfLongestPathPassing
47+ ,dependency
48+ ,source
49+ ,target
50+ // If there is at least one longest path passing through the dependency then "contributesToALongestPath" is true
51+ ,([source , target ] IN allLongestPathStartAndEndNodeTuples ) AS contributesToALongestPath
52+ ,([source , target ] IN longestPathStartAndEndNodeTuples ) AS isPartOfLongestPath
53+ WITH * , dependency [$dependencies_projection_weight_property ] AS weight
54+ WITH * , toFloat (weight - minWeight ) * weightNormalizationFactor AS normalizedWeight
55+ WITH * , round ((normalizedWeight * 5 ) + 1 , 2 ) AS penWidth
56+ WITH * , source .name + "\\ n(level " + source .maxDistanceFromSource + "/" + maxLevel + ")" AS startNodeTitle
57+ WITH * , target .name + "\\ n(level " + target .maxDistanceFromSource + "/" + maxLevel + ")" AS endNodeTitle
58+ // The longest path will be highlighted in red.
59+ WITH * , CASE WHEN isPartOfLongestPath THEN "; color=\" red\" "
60+ // Dependencies contributing to the longest path will be highlighted in dark orange.
61+ WHEN contributesToALongestPath THEN "; color=\" darkorange\" "
62+ ELSE "" END AS edgeColor
63+ WITH * , "[label=" + weight + "; penwidth=" + penWidth + edgeColor + "; ];" AS graphVizEdgeAttributes
64+ WITH * , "\" " + startNodeTitle + "\" -> \" " + endNodeTitle + "\" " + graphVizEdgeAttributes AS graphVizDotNotationLine
65+ RETURN DISTINCT graphVizDotNotationLine
66+ // Debugging
67+ // ,source.name
68+ // ,target.name
69+ // ,numberOfLongestPathsPassing
70+ // ,lengthOfLongestPathPassing
71+ // ,contributesToALongestPath
72+ // ,isPartOfLongestPath
73+ LIMIT 100
0 commit comments