Graph Neo4J/Cypher:如何过滤路径的节点?
我想得到一个图上经过给定节点的所有Graph Neo4J/Cypher:如何过滤路径的节点?,graph,neo4j,cypher,Graph,Neo4j,Cypher,我想得到一个图上经过给定节点的所有简单循环/电路。通过这个密码查询,我能够做到: MATCH p=(n)-[*]->(n) WHERE n.postId = 71 //postId is a node property RETURN nodes(p) 但是,上面检索的是“回路”中的重复节点(起点和终点节点除外),根据图论,该回路根本不是回路 通过以下查询,我可以删除电路中的重复项,但我必须限制匹配模式中电路或路径的长度,这是一种硬编码模式 // In this example the l
简单循环
/电路
。通过这个密码查询,我能够做到:
MATCH p=(n)-[*]->(n)
WHERE n.postId = 71 //postId is a node property
RETURN nodes(p)
但是,上面检索的是“回路”中的重复节点(起点和终点节点除外),根据图论,该回路根本不是回路
通过以下查询,我可以删除电路中的重复项,但我必须限制匹配
模式中电路或路径的长度,这是一种硬编码模式
// In this example the length of the path is hardcoded to 4
MATCH p=
(n)-[:RELATES_TO]->
(p2)-[:RELATES_TO]->
(p3)-[:RELATES_TO]->
(p4)-[:RELATES_TO]->(n)
WHERE n.postId = 71
AND p2.postId <> 71
AND p3.postId <> 71
AND p4.postId <> 71
RETURN nodes(p)
重要提示:
- 我知道如何限制路径的长度(通过WHERE length()约束或with)
但是,如果将结束节点定义为循环中倒数第二步,即与开始节点具有定向关系的开始节点的所有相邻节点,则您应该能够获得结果(尽管路径显然不包括完成循环的开始节点的最终遍历).尽管这可能不如使用AllSimplePath APOC过程快,正如@InverseFalcon所建议的那样(我还没有尝试过),但这里有一个方法可以在纯密码中获得简单路径:
MATCH p=(n)-[*]->(n)
WHERE n.postId = 71
WITH NODES(p) AS nds
UNWIND nds AS nd
WITH nds, COUNT(DISTINCT nd) AS dnd
WHERE dnd = LENGTH(nds)-1
RETURN nds;
基本上,此查询要求路径中的不同节点数等于节点数减去1(因为最后一个节点必须与第一个节点相同)。是否尝试使用或?我想我正确地理解了您的问题,但以下是我如何使用上述函数。(如果此选项处于关闭状态,则只需按下即可。)
要点:
但这不是OP的问题。)
(1) 获取从一个人到一个电话号码的所有可能路径(为可读性而编辑):
(2) 使用
none()
通过筛选出包含特定节点(具有特定属性或标签的节点)的路径来删除冗余:
(3) 使用
filter()
从返回的路径中删除特定节点:
MATCH path = (p:Person)-[*]-(n:PhoneNumber)
WITH nodes(path) as ns
WHERE NONE(node IN ns WHERE (exists(node.name) and node.name ='Gorduin'))
RETURN filter(node in ns WHERE NOT node:Person) as personless_nodelist;
╒══════════════════════════════════════════════════════════════╕
│"personless_nodelist" │
╞══════════════════════════════════════════════════════════════╡
│[pn] │
├──────────────────────────────────────────────────────────────┤
│[e19,pn] │
└──────────────────────────────────────────────────────────────┘
谢谢@InverseFalcon,我来看看。不知道有这么神奇的插件存在…!:)我以这种方式执行
allSimplePaths
过程MATCH(from:Post{postId:71}),(to:Post{postId:71})调用apoc.algo.allSimplePaths(from,to,'related_to',5)产生路径返回*
它返回一个节点,这个节点的属性postId=71
很不幸。我明天会在上面记录一个bug。我为此创建了一个。我还更新了我的答案,加入了一个仍然使用所有SimplePath的解决方案。如果我错了,请纠正我,这似乎会计算所有允许重复的简单路径,然后删除具有重复节点的路径。这是正确的吗?在Cypher中,您不能影响可变长度关系的遍历(这是必须的,Cypher是声明性的),因此任何解决方案都必须在事实发生后进行过滤。使用Java,您可以在找到重复的路径后立即停止超出给定路径的遍历,包括与开始节点相同的结果,否则将其排除在外。
CREATE
(g:Person {name: 'Gorduin'}), (a:Person {name: 'Alvaro'}),
(pn:PhoneNumber {number: '555-512-2017'}),
(e11:Extension {extension: 11}),
(e27:Extension {extension: 27}),
(e19:Extension {extension: 19}),
(e11)-[:extension_of]->(pn)<-[:extension_of]-(e27),
(e19)-[:extension_of]->(pn),
(g)<-[:phone_number_of]-(e11),
(g)<-[:phone_number_of]-(e27),
(a)<-[:phone_number_of]-(e19),
(a)<-[:phone_number_of]-(pn);
MATCH path = (p:Person)-[*1..3]-(n:PhoneNumber)
RETURN nodes(path);
MATCH path = (p:Person)-[*]-(n:PhoneNumber)
RETURN nodes(path) as every_possible_path_from_a_Person_to_a_PhoneNumber;
╒══════════════════════════════════════════════════════════════════════╕
│"every_possible_path_from_a_Person_to_a_PhoneNumber" │
╞══════════════════════════════════════════════════════════════════════╡
│[a,pn] │
├──────────────────────────────────────────────────────────────────────┤
│[g,e11,pn,e19,a,pn] │
├──────────────────────────────────────────────────────────────────────┤
│[g,e27,pn,e19,a,pn] │
├──────────────────────────────────────────────────────────────────────┤
│[g,e11,pn] │
├──────────────────────────────────────────────────────────────────────┤
│[a,pn,e27,g,e11,pn] │
├──────────────────────────────────────────────────────────────────────┤
│[a,e19,pn,e27,g,e11,pn] │
├──────────────────────────────────────────────────────────────────────┤
│[a,e19,pn] │
├──────────────────────────────────────────────────────────────────────┤
│[g,e11,pn,a,e19,pn] │
├──────────────────────────────────────────────────────────────────────┤
│[g,e27,pn,a,e19,pn] │
├──────────────────────────────────────────────────────────────────────┤
│[g,e27,pn] │
├──────────────────────────────────────────────────────────────────────┤
│[a,pn,e11,g,e27,pn] │
├──────────────────────────────────────────────────────────────────────┤
│[a,e19,pn,e11,g,e27,pn] │
└──────────────────────────────────────────────────────────────────────┘
MATCH path = (p:Person)-[*]-(n:PhoneNumber)
WITH nodes(path) as ns
WHERE NONE(node IN ns WHERE (exists(node.name) and node.name ='Gorduin'))
RETURN ns as path_nodes_NOT_containing_a_specific_person;
╒══════════════════════════════════════════════════════════════╕
│"path_nodes_NOT_containing_a_specific_person" │
╞══════════════════════════════════════════════════════════════╡
│[a,pn] │
├──────────────────────────────────────────────────────────────┤
│[a,e19,pn] │
└──────────────────────────────────────────────────────────────┘
MATCH path = (p:Person)-[*]-(n:PhoneNumber)
WITH nodes(path) as ns
WHERE NONE(node IN ns WHERE (exists(node.name) and node.name ='Gorduin'))
RETURN filter(node in ns WHERE NOT node:Person) as personless_nodelist;
╒══════════════════════════════════════════════════════════════╕
│"personless_nodelist" │
╞══════════════════════════════════════════════════════════════╡
│[pn] │
├──────────────────────────────────────────────────────────────┤
│[e19,pn] │
└──────────────────────────────────────────────────────────────┘