Finding cypher paths that don't visit the same node twice

自作多情 提交于 2019-12-13 03:03:44

问题


I'm looking for the paths between two nodes in a graph, but my graph has a loop in it and so I'm getting paths back that are undesirable. I'm hoping that someone here can help me think out a sensible remedy.

Here's my graph:

A
|
2
|
C-3-D
|   |
|   4
5   |
|   E
|   |
|   6
|   |
F-7-G

The letters are nodes, and the numbers are edges (relationships).

CREATE (a {i: "A"})
CREATE (c {i: "C"})
CREATE (d {i: "D"})
CREATE (e {i: "E"})
CREATE (f {i: "F"})
CREATE (g {i: "G"})
CREATE a-[:r {i:2}]->c-[:r {i:3}]->d-[:r {i:4}]->e-[:r {i:6}]->g
CREATE c-[:r {i:5}]->f-[:r {i:7}]->g;

I'm looking for paths between A and C, and I'd only expect there to be one, but there are three!

neo4j-sh (?)$ MATCH p=({i: "a"})-[:r*]-({i: "c"}) return EXTRACT(n IN NODES(p) | n.i);
+-------------------------------+
| EXTRACT(n IN NODES(p) | n.i)  |
+-------------------------------+
| ["A","C"]                     |
| ["A","C","D","E","G","F","C"] |
| ["A","C","F","G","E","D","C"] |
+-------------------------------+

neo4j-sh (?)$ MATCH p=({i: "a"})-[:r*]-({i: "c"}) return EXTRACT(n IN RELATIONSHIPS(p) | n.i);
+--------------------------------------+
| EXTRACT(n IN RELATIONSHIPS(p) | n.i) |
+--------------------------------------+
| [2]                                  |
| [2,3,4,6,7,5]                        |
| [2,5,7,6,4,3]                        |
+--------------------------------------+

That makes sense from a graph perspective because the path isn't visiting the same edge twice, but from a node perspective it's a pain because C clearly is visited twice.

One thought was to try shortest paths, using allShortestPaths, however that only appears to filter the result by returning just the shortest length paths, which isn't the same as avoiding passing through the same node twice. For example the route A->G has two paths:

"A" -> "G" : [[2, 5, 7], [2, 3, 4, 6]]

but when I use allShortestPaths I only get the three hop path [2,5,7].

Is there a sensible way of applying a restriction so that I only get paths where each node is only visited once?


回答1:


I think you should use shortestPath or allShortestPaths, like this:

MATCH p=shortestPath((:Label1 {i: "a"})-[:r*]-(:Label2 {i: "c"})) 
RETURN EXTRACT(n IN NODES(p) | n.i);

make sure to create an index/constraint for :Label(i)

you can try something like that (filter out all paths where a node appears twice)

MATCH p=({ i: "A" })-[:r*]-({ i: "C" })
WHERE NONE (n IN nodes(p) 
            WHERE size(filter(x IN nodes(p) 
                              WHERE n = x))> 1)
RETURN EXTRACT(n IN RELATIONSHIPS(p)| n.i);

the index hint was an optimization for a real world dataset



来源:https://stackoverflow.com/questions/28261198/finding-cypher-paths-that-dont-visit-the-same-node-twice

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!