Neo4j 如何编写查询来比较不同路径上的节点和边?
我们对Neo4j还不熟悉(而且很兴奋!),我正在尝试将Cypher应用到我们的问题中。我们有一个匹配路径的查询,但它需要删除涉及在源自同一节点或边的任何其他路径上遍历的任何节点或边的路径。下面是一个测试用例:Neo4j 如何编写查询来比较不同路径上的节点和边?,neo4j,cypher,Neo4j,Cypher,我们对Neo4j还不熟悉(而且很兴奋!),我正在尝试将Cypher应用到我们的问题中。我们有一个匹配路径的查询,但它需要删除涉及在源自同一节点或边的任何其他路径上遍历的任何节点或边的路径。下面是一个测试用例: CREATE (a1:A {name: 'a1'})-[ab1:AB {name: 'ab1'}]->(b1:B {name: 'b1'}), (a1)-[ab2:AB {name: 'ab2'}]->(b2:B {name: 'b2'}), (a2
CREATE (a1:A {name: 'a1'})-[ab1:AB {name: 'ab1'}]->(b1:B {name: 'b1'}),
(a1)-[ab2:AB {name: 'ab2'}]->(b2:B {name: 'b2'}),
(a2:A {name: 'a2'})-[ab3:AB {name: 'ab3'}]->(b1),
(a2)-[ab5:AB {name: 'ab5'}]->(b3:B {name: 'b3'}),
(a3:A {name: 'a3'})-[ab4:AB {name: 'ab4'}]->(b2),
(a3)-[ab6:AB {name: 'ab6'}]->(b3),
(a4:A {name: 'a4'})-[ab7:AB {name: 'ab7'}]->(b3);
为可读性而格式化:
a1-[ab1]->b1
a1-[ab2]->b2
a2-[ab3]->b1
a2-[ab5]->b3
a3-[ab4]->b2
a3-[ab6]->b3
a4-[ab7]->b3
我们想找到以下路径:[A,AB,B,AB,A,AB,B,AB,A](四个步骤)。(注意:我们不关心边的方向性。)下面是我的第一次尝试(我们的术语:i_id='initial'和t_id='terminal')
考虑到Cypher的特点,结果是合理的:
但是,我们需要额外的过滤。考虑IIID.No.=“A2”:
+-------------------------------------------------------------------------------------------------+
| i_id.name | ab1.name | b1.name | ab2.name | a1.name | ab3.name | b2.name | ab4.name | t_id.name |
+-------------------------------------------------------------------------------------------------+
| "a2" | "ab3" | "b1" | "ab1" | "a1" | "ab2" | "b2" | "ab4" | "a3" |
| "a2" | "ab5" | "b3" | "ab6" | "a3" | "ab4" | "b2" | "ab2" | "a1" |
+-------------------------------------------------------------------------------------------------+
请注意,第一个路径如何包含ab4.name=“ab4”,在第二个路径上也可以找到ab3.name。相反,“ab2”在第二条路径上显示为ab4.name,在第一条路径上显示为ab3.name。在我们的应用程序中,我们希望这两个函数“取消”,以便查询不会返回a2的匹配项
最后,我的问题是:你将如何在Cypher中实现这一点?多个查询只要执行速度快就可以了:-)我对Cypher是个新手,但我认为可能有用的一些东西是(抓稻草,这里:-)
- 将路径作为集合进行比较(类似于WHERE ab4.name NOT 在…?)
- 为项目添加标签/属性表示i_id和 他们在哪条路上
- 每个人
- 放松
- 分组
我们希望尽可能多地使用Cypher,但是如果答案是“你不能这样做”,那么我们将把上面的候选结果拉入内存并在那里完成处理。非常感谢 因此,我利用您的第二个建议制定了一个解决方案,即向关系中添加属性,以指示它们是否位于两条或多条路径上 首先,在每个
AB
关系上创建一个traversed
属性,并将其设置为0
:
MATCH ()-[ab:AB]-()
SET ab.traversed = 0
现在我将使用a2
作为示例的起始节点。此查询查找从a2
到另一个标签为A
且长度为四步的节点的所有路径。每个关系的traversed
属性设置为该关系在路径上遇到的次数
MATCH p = (a2:A {name:'a2'})-[:AB*4]-(:A)
UNWIND RELATIONSHIPS(p) AS r
WITH r, COUNT(*) AS times_traversed
SET r.traversed = times_traversed
RETURN r.name, r.traversed
ORDER BY r.name
我们得到以下输出:
正如您在示例中所解释的,ab2
和ab4
都在这两条路径上,因此它们的遍历属性是2
通过在每个关系上设置这些属性,您可以仅将路径过滤到其所遍历的属性之和等于路径长度(在您的情况下为4)的路径
MATCH p = (a2:A {name:'a2'})-[:AB*4]-(:A)
WHERE REDUCE(traversal = 0, r IN RELATIONSHIPS(p) | traversal + r.traversed) = LENGTH(p)
RETURN p
这不会返回任何路径,因为两条路径的遍历的属性之和都是6
,而不是所需的4
但正如我所说,这是非常不雅观的,可能有更好的方法来做到这一点。在a2示例中,当你说“取消”时,你只想返回一条路径,还是两者都不想返回?@NicoleWhite两条路径都不应该符合条件,也就是说,a2不应该返回任何行。谢谢,好的。在重读了几遍之后,我想我明白了。我已经想出了一个解决办法,但它很不雅观。我现在就把它打出来。非常感谢你,妮可。我认为这是我追求的一个很好的方向。
MATCH p = (a2:A {name:'a2'})-[:AB*4]-(:A)
UNWIND RELATIONSHIPS(p) AS r
WITH r, COUNT(*) AS times_traversed
SET r.traversed = times_traversed
RETURN r.name, r.traversed
ORDER BY r.name
MATCH p = (a2:A {name:'a2'})-[:AB*4]-(:A)
WHERE REDUCE(traversal = 0, r IN RELATIONSHIPS(p) | traversal + r.traversed) = LENGTH(p)
RETURN p