如何避免路径Neo4j Cypher中的循环或循环

时间:2017-11-09 09:30:02

标签: neo4j cypher

我使用路径变量时遇到问题。

例如,我的层次结构看起来像

A-[Knows]-> B   
B-[Knows]-> C  
C-[Knows]-> D  
D-[Knows]-> E  
C-[Knows]-> F  
F-[Knows]-> G  
G-[Knows]-> B 

我的查询是MATCH p = (x)<-[Knows*]->(y) Return p

关系方向必须是双向的。玩具问题就像A,B,但在实际应用中,我不知道关系的方向。

所以有一个循环和循环。路径开始从A到C找到。但是在找到C后,接下来的步骤,循环就发生了。

如何避免循环或如何忽略它,如何从实际路径中删除或如何在路径以B结尾时停止。我不需要找到第二个B到C。

预期结果:

A->B->C->D->E
A->B->C->F->G->B  // that is enough. The query must be stopped.

实际结果:

A->B->C->D->E
A->B->C->F->G->B->C->F->G->B..... loop trouble.

3 个答案:

答案 0 :(得分:3)

我们如何验证路径是否包含循环?

清除密码的一种简单方法是计算路径中唯一节点的数量,并将其与增加1的路径长度进行比较:

MATCH path = (x)-[:KNOWS*]-(y)
  UNWIND NODES(path) AS n
    WITH path, 
         SIZE(COLLECT(DISTINCT n)) AS testLength 
    WHERE testLength = LENGTH(path) + 1
RETURN path

您可以使用APOC library中的集合函数简化查询。

例如:

MATCH path = (x)-[:KNOWS*]-(y)
      WHERE SIZE(apoc.coll.toSet(NODES(path))) > LENGTH(path) + 1
RETURN path

或者我们可以简化:

MATCH path = (x)-[:KNOWS*]-(y) 
      WHERE apoc.coll.duplicates(NODES(path)) = []
RETURN path

答案 1 :(得分:2)

首先,为了避免循环,cypher具有以下机制:在模式中,只能在关系中遍历。

您的查询问题是您正在搜索所有节点之间的所有路径(这就是为什么需要一些时间)。

如果您只想搜索两个节点之间的shortespath,可以使用cypher的shortespath函数:MATCH p = shortestpath((x)-[Knows*]-(y)) RETURN p

此外,如果你现在是结束节点,你应该告诉它为cypher:

MATCH p = shortestpath((x)-[Knows*]-(y)) 
WHERE x.name = 'A' AND y.name = 'B'
RETURN p

干杯

答案 2 :(得分:0)

这是一个可以达到理想结果的例子。

有几点需要注意。我从节点A开始,而不是在整个图表中应用模式。为了用cypher得到你想要的结果,我按照指示查询了KNOWS的关系。如果你删除方向,那么你得到更多的结果,我不确定是不正确的。无论如何,你可以自己决定。

查询找到所有路径,然后将那些包含在最长不同路径中的路径计算出来。

首先我从一些小数据开始......

CREATE (A:Person {name: 'A'})
CREATE (B:Person {name: 'B'})
CREATE (C:Person {name: 'C'})
CREATE (D:Person {name: 'D'})
CREATE (E:Person {name: 'E'})
CREATE (F:Person {name: 'F'})
CREATE (G:Person {name: 'G'})
CREATE (A)-[:KNOWS]->(B)
CREATE (B)-[:KNOWS]->(C)   
CREATE (C)-[:KNOWS]->(D)  
CREATE (D)-[:KNOWS]->(E)  
CREATE (C)-[:KNOWS]->(F)  
CREATE (F)-[:KNOWS]->(G)  
CREATE (G)-[:KNOWS]->(B)
RETURN *

这是查询

// find all the variable length paths starting with A
MATCH path = (x:Person)-[:KNOWS*]->(y:Person)
WHERE x.name = 'A'

// collect the paths and collect the paths excluding the last node
WITH COLLECT(path) AS paths,
     COLLECT(DISTINCT nodes(path)[0..size(nodes(path))-1]) AS all_but_last_nodes_of_paths

// filter the paths out that are already included (i.e. shorter ones)
WITH [p IN paths WHERE NOT nodes(p) IN all_but_last_nodes_of_paths] AS paths_to_keep

// return each path to keep
UNWIND paths_to_keep AS path
WITH reduce(path_txt = "", n in nodes(path) | path_txt + n.name + "->") AS path_txt
RETURN left(path_txt,size(path_txt)-2) AS path_txt

以下是用APOC解决的相同查询,而不仅仅是使用expandConfig的cypher。请注意,它还依赖于在查询时指定方向以获得所需的结果集。

MATCH (x:Person)
WHERE x.name = 'A'
WITH x
CALL apoc.path.expandConfig(x, {
                                relationshipFilter:'KNOWS>',
                                labelFilter:'+Person',
                                uniqueness: 'RELATIONSHIP_PATH'
                           } ) YIELD path AS path
WITH COLLECT(path) AS paths,
     COLLECT(DISTINCT nodes(path)[0..size(nodes(path))-1]) AS all_but_last_nodes_of_paths
WITH [p IN paths WHERE NOT nodes(p) IN all_but_last_nodes_of_paths] AS paths_to_keep
UNWIND paths_to_keep AS path
WITH reduce(path_txt = "", n in nodes(path) | path_txt + n.name + "->") AS path_txt
RETURN left(path_txt,size(path_txt)-2) AS path_txt