我使用路径变量时遇到问题。
例如,我的层次结构看起来像
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.
答案 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