1+ // Anomaly Detection Graphs: Find top nodes marked as "hub" including their incoming dependencies and output them in Graphviz format.
2+
3+ // Step 1: Query overall statistics, e.g. min/max weight for later normalization
4+ MATCH (sourceForStatistics )- [ dependencyForStatistics : DEPENDS_ON ] -> (targetForStatistics )
5+ WHERE $projection_node_label IN labels (sourceForStatistics )
6+ AND $projection_node_label IN labels (targetForStatistics )
7+ WITH min (coalesce (dependencyForStatistics .weight25PercentInterfaces , dependencyForStatistics .weight )) AS minWeight
8+ ,max (coalesce (dependencyForStatistics .weight25PercentInterfaces , dependencyForStatistics .weight )) AS maxWeight
9+ // Step 2: Query direct dependencies to the target
10+ MATCH (source )- [ directDependency : DEPENDS_ON ] -> (target )
11+ WHERE $projection_node_label IN labels (source )
12+ AND $projection_node_label IN labels (target )
13+ AND target .anomalyScore > 0
14+ AND target .anomalyHubRank = toInteger ($projection_node_rank )
15+ ORDER BY directDependency .weight DESC
16+ WITH minWeight
17+ ,maxWeight
18+ ,target
19+ ,collect (source )[0 ..60 ] AS sources
20+ ,collect (directDependency )[0 ..60 ] AS directDependencies
21+ // Step 3: Query dependencies among sources
22+ UNWIND sources AS source1
23+ UNWIND sources AS source2
24+ MATCH (source1 )- [ indirectDependency : DEPENDS_ON ] -> (source2 )
25+ WITH minWeight
26+ ,maxWeight
27+ ,target
28+ ,directDependencies
29+ ,collect (indirectDependency ) AS indirectDependencies
30+ WITH * , directDependencies + indirectDependencies AS allDependencies
31+ // Step 4: Prepare results in GraphViz format for all dependencies
32+ UNWIND allDependencies AS dependency
33+ WITH * , (endNode (dependency ) = target ) AS isTargetEndNode
34+ WITH * , CASE WHEN isTargetEndNode THEN endNode (dependency ) ELSE null END AS targetEndNodeOrNull
35+ WITH * , CASE WHEN isTargetEndNode THEN null ELSE endNode (dependency ) END AS nonTargetEndNodeOrNull
36+ WITH * , coalesce (dependency .weight25PercentInterfaces , dependency .weight ) AS weight
37+ WITH * , toFloat (weight - minWeight ) / toFloat (maxWeight - minWeight ) AS normalizedWeight
38+ WITH * , round ((normalizedWeight * 2 ) + 0.4 , 1 ) AS penWidth
39+ WITH * , coalesce (target .fqn , target .globalFqn , target .fileName , target .signature , target .name ) AS targetName
40+ WITH * , replace (replace (targetName , '.' , '.\\ n' ), '/' , '/\\ n' ) AS targetNameSplit
41+ WITH * , "\\ n(hub #" + targetEndNodeOrNull .anomalyHubRank + ")" AS hubSubLabel
42+ WITH * , "\" " + targetNameSplit + hubSubLabel + "\" " AS hubLabel
43+ WITH * , coalesce ("\" hub\" [label=" + hubLabel + ";]; " , "" ) AS hubNode
44+ WITH * , "\" " + startNode (dependency ).name + "\" " AS sourceNode
45+ WITH * , coalesce ("\" " + nonTargetEndNodeOrNull .name + "\" " , "\" hub\" " ) AS targetNode
46+ WITH * , " -> " + targetNode
47+ + " [label = " + weight + ";"
48+ + " penwidth = " + penWidth + ";"
49+ + " ];" AS graphVizDotNotationEdge
50+ WITH * , hubNode + sourceNode + coalesce (graphVizDotNotationEdge , " [];" ) AS graphVizDotNotationLine
51+ ORDER BY target .anomalyHubRank DESC , target .name ASC
52+ RETURN DISTINCT graphVizDotNotationLine
53+ //Debugging
54+ //,startNode(dependency).name AS sourceName
55+ //,endNode(dependency).name AS targetName
56+ //,hubNode
57+ //,penWidth
58+ //,normalizedWeight
59+ //,dependency.weight AS weight
60+ //,minWeight
61+ //,maxWeight
62+ LIMIT 100
0 commit comments