我可能过于复杂了,但给出了一些看起来接近您的图表的示例数据:
MERGE (sd: Node { name: 'SD' })
MERGE (ssd: Node { name: 'SSD' })
MERGE (ld: Node { name : 'LD' })
MERGE (ceo: Node { name: 'CEO' })
MERGE (cto: Node { name: 'CTO' })
MERGE (st: Node { name: 'ST' })
MERGE (vf: Node { name: 'VF' })
MERGE (bo: Node { name: 'BO' })
MERGE (md: Node { name: 'MD' })
MERGE (bb: Node { name: 'BB' })
MERGE (sd)-[:NEXTEXP { id: 1 }]->(ssd)
MERGE (ssd)-[:NEXTEXP { id: 1 }]->(ld)
MERGE (ld)-[:NEXTEXP { id: 1 }]->(ceo)
MERGE (sd)-[:NEXTEXP { id: 2 }]->(ssd)
MERGE (ssd)-[:NEXTEXP { id: 2 }]->(ld)
MERGE (ssd)-[:NEXTEXP { id: 2 }]->(vf)
MERGE (ssd)-[:NEXTEXP { id: 2 }] ->(bo)
MERGE (sd)-[:NEXTEXP { id: 3 }]->(st)
MERGE (st)-[:NEXTEXP { id: 3 }]->(bo)
MERGE (bo)-[:NEXTEXP { id: 3 }]->(cto)
MERGE (sd)-[:NEXTEXP { id: 4 }]->(st)
MERGE (st)-[:NEXTEXP { id: 4 }]->(md)
MERGE (st)-[:NEXTEXP { id: 5 }]->(bb)
以下似乎产生了正确的答案:
MATCH path=(s: Node { name: 'SD' })-[:NEXTEXP*1..2]->(other: Node)
WITH distinct nodes(path) as pathNodes,
relationships(path) as pathRels,
reduce(minValue = head(relationships(path)).id, x in relationships(path) | (case when x.id = minValue then x.id else null end)) as pathRelIds
WHERE pathRelIds IS NOT NULL
WITH pathNodes, count(pathNodes) as ct, size(pathNodes) as pathLength
RETURN pathLength as `Length`, pathNodes as `Paths`, ct as `Count`
ORDER BY `Length`, `Paths`, `Count`
该查询假定您需要关系的 ID 在整个路径中相同。这似乎是您要问的,因为在您的“预期”表中 SD -> SSD -> LD 的计数为 2,而不是 3。
稍微分解一下:
- 我们匹配 1 到 2 个关系,并将结果路径分配给名为
path 的变量
- 第二行中的
reduce 调用尝试返回路径中最小的关系 ID,或者如果有多个关系 ID,则返回 NULL - 这有点欺骗,取决于 Cypher 如何处理 NULL在表达式中
- 第三行消除了前一个
reduce 返回 NULL 的情况 - 也就是说,我们消除了路径中的关系中存在多个 ID 的路径
对于您要求的 exact 输出(节点名称连接成单个字符串),以下修改后的查询:
MATCH path=(s: Node { name: 'SD' })-[:NEXTEXP*1..2]->(other: Node)
WITH distinct s,
nodes(path) as pathNodes,
relationships(path) as pathRels,
reduce(minValue = head(relationships(path)).id, x in relationships(path) | (case when x.id = minValue then x.id else null end)) as pathRelIds
WHERE pathRelIds IS NOT NULL
WITH s, pathNodes, count(pathNodes) as ct, size(pathNodes) as pathLength
RETURN pathLength as `Length`,
reduce(pathStr = s.name, x in pathNodes[1..] | pathStr + ' --> ' + x.name) as `Paths`,
ct as `Count`
ORDER BY `Length`, `Count` DESC, `Paths`
产生以下输出:
╒════════╤═══════════════════╤═══════╕
│"Length"│"Paths" │"Count"│
╞════════╪═══════════════════╪═══════╡
│2 │"SD --> SSD" │2 │
├────────┼───────────────────┼───────┤
│2 │"SD --> ST" │2 │
├────────┼───────────────────┼───────┤
│3 │"SD --> SSD --> LD"│2 │
├────────┼───────────────────┼───────┤
│3 │"SD --> SSD --> BO"│1 │
├────────┼───────────────────┼───────┤
│3 │"SD --> SSD --> VF"│1 │
├────────┼───────────────────┼───────┤
│3 │"SD --> ST --> BO" │1 │
├────────┼───────────────────┼───────┤
│3 │"SD --> ST --> MD" │1 │
└────────┴───────────────────┴───────┘
这与您的预期仅不同之处在于 SD --> SSD --> BO 行,这可能是由于我误解了您的图表。