[英]Find and count all possible paths starting from one node not exceeding specific length in Cypher Neo4j
I have a graph with several nodes connected with two possible relationships: NextExp and PrevExp. 我有一个图,图中有几个节点连接着两个可能的关系:NextExp和PrevExp。 Each relationship has a specific ID, so it is possible to have multiple relationships between two nodes. 每个关系都有一个特定的ID,因此在两个节点之间可能有多个关系。
ID1 ID1 ID1
SD ---> SSD ---> LD ---> CEO
ID2 ID2
SD ---> SSD ---> LD
ID2 ID2
SD ---> SSD ---> VF
ID2
SSD ---> BO
ID3 ID3 ID3
SD ---> ST ---> BO ---> CTO
ID4 ID4
SD ---> ST ---> MD
ID5
ST ---> BB
I want to find (actually count) all possible paths with specific lengths starting from node SD, counting only a specific relationship (ie NextExp for instance). 我想查找(实际上计算)从节点SD开始具有特定长度的所有可能路径,仅计算特定关系(例如NextExp)。 For the example above, if the max length is 3, I would like to have something like this: 对于上面的示例,如果最大长度为3,则我想要这样的内容:
Length | Paths | Count
2 SD --> SSD 2
SD --> ST 2
3 SD --> SSD --> LD 2
SD --> SSD --> VF 1
SD --> ST --> BO 1
SD --> ST --> MD 1
Being new in Neo4j, I tried using MATCH but could not find how to not specify an ending node when searching for paths. 作为Neo4j中的新手,我尝试使用MATCH,但是在搜索路径时找不到如何不指定结束节点。
I might be overcomplicating this, but given some sample data that looks close to your diagram: 我可能对此过于复杂,但是给出了一些看起来与您的图表很接近的示例数据:
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)
The following appears to yield the right sort of answer: 以下显示出正确的答案:
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`
The query assumes that you need the ID of the relationships to be the same throughout the path. 该查询假定您需要在整个路径中关系的ID 相同 。 This seemed to be what you're asking since in your 'expected' table SD -> SSD -> LD has a count of 2, rather than 3. 这似乎是您要问的问题,因为在“期望”表中SD-> SSD-> LD的计数为2,而不是3。
Breaking it down a bit: 分解一下:
path
我们在1和2关系之间进行匹配,并将结果路径分配给名为path
的变量 reduce
call in the second line tries to return either the smallest relationship ID within the path, or NULL
if there are multiple relationship IDs - it's a bit of a cheat that relies on how Cypher treats NULL
in expressions 该reduce
在第二行调用试图返回一个路径中的最小关系ID,或NULL
如果有多个关系的标识-这是一个有点依赖于如何对待Cypher支架作弊的NULL
表达式 reduce
returned NULL
- that is, we eliminate paths where there's more than one ID on the relationships in the path 第三行消除了先前reduce
返回NULL
-也就是说,我们消除了路径中的关系上有多个ID的路径 For the exact output you're asking for (where the names of nodes are joined into a single string), the following amended query: 对于您要求的确切输出(将节点名称连接到单个字符串中),请进行以下修改的查询:
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`
Yields the following output: 产生以下输出:
╒════════╤═══════════════════╤═══════╕
│"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 │
└────────┴───────────────────┴───────┘
Which differs from your expected only by the SD --> SSD --> BO row, which is probably due to me misinterpreting your diagram. 这与您仅通过SD-> SSD-> BO行所期望的不同,这可能是由于我误解了您的图表。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.