How to query exact path in neo4j and avoid cartesian product?

[亡魂溺海] 提交于 2021-01-29 09:36:58

问题


I have around 3000 nodes with 7000 relationships in a graph but for a presentation, I'd like to plot a sub-graph of which I know exactly which nodes I need.

Therefore, I use the following query which sometimes gives me the correct path as a result (after a long waiting period) and sometimes depletes memory and cpu resources until I force-quit the neo4j-browser.

MATCH p1=(:DestinationNode)-[:IS_AT]->
(:CentiDegreeNode{x: 4714, y: 843})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4715, y: 843})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4716, y: 843})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4717, y: 843})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4718, y: 843})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4718, y: 844})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4719, y: 844}),
p2=(:DestinationNode)-[:IS_AT]->
(:CentiDegreeNode{x: 4718, y: 839})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4718, y: 840})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4719, y: 840})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4719, y: 841})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4719, y: 842})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4719, y: 843})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4719, y: 844}),
p3=(:CentiDegreeNode{x: 4719, y: 844})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4719, y: 845})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4719, y: 846})
RETURN p1, p2, p3

What am I doing wrong? How would I have to rephrase the query in order to have it executed within seconds? Note that x and y of a CentiDegreeNode are indexed.

Initially I started with directed relationships (-[:CONNECTED_TO]->) but this wasn't any quicker.

Thank you very much!


回答1:


When you say that "x and y of a CentiDegreeNode are indexed", hopefully you meant that both properties are used together in a single index: :CentiDegreeNode(x, y). That would be more performant.

Separating the 3 paths by WITH clauses might help (this could depend on the version of neo4j). Also, by collecting the paths along the way, you can avoid cartesian products.

MATCH p1=(:DestinationNode)-[:IS_AT]->
(:CentiDegreeNode{x: 4714, y: 843})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4715, y: 843})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4716, y: 843})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4717, y: 843})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4718, y: 843})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4718, y: 844})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4719, y: 844})
WITH COLLECT(p1) AS p1s
MATCH p2=(:DestinationNode)-[:IS_AT]->
(:CentiDegreeNode{x: 4718, y: 839})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4718, y: 840})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4719, y: 840})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4719, y: 841})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4719, y: 842})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4719, y: 843})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4719, y: 844})
WITH p1s, COLLECT(p2) AS p2s
MATCH p3=(:CentiDegreeNode{x: 4719, y: 844})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4719, y: 845})-[:CONNECTED_TO*1]-
(:CentiDegreeNode{x: 4719, y: 846})
RETURN p1s, p2s, COLLECT(p3) AS p3s



回答2:


You can rephrase your query to avoid Cartesian product by using UNION

match path=(:A)-[:K]->(:B) 
return path
union
match path=(:D)-[:H]->(:C) 
return path
union
match path=(:F)-[:L]->(:G}) 
return path

This returns list of all the paths, which is good enough to plot graph with out cartesian.

But, This way you can not differentiate which path is of which type if we need to use such information in our application code. So we need to modify this query a bit(lil computationally expensive than last one). For achieving classification of paths by piping intermediate results using WITH.

match path=(:A)-[:K]->(:B) 
with collect( path)  as path_list_1
match path=(:D)-[:H]->(:C) 
with path_list_1, collect( path)  as path_list_2
match path=(:F)-[:L]->(:G})
with path_list_1, path_list_2 , collect( path)  as path_list_3
return path_list_1, path_list_2 , path_list_3

Now with this we can achieve optimal collection and classification of paths.

If you are on older version where WITH is not available, then you can do something like this and then aggregate based on path_types in your application.

match path=(:A)-[:K]->(:B) 
return path, 1 as path_type
union
match path=(:D)-[:H]->(:C) 
return path, 2 as path_type
union
match path=(:F)-[:L]->(:G}) 
return path, 3 as path_type 

Cheers!!



来源:https://stackoverflow.com/questions/55948231/how-to-query-exact-path-in-neo4j-and-avoid-cartesian-product

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