2017-05-23 113 views
2
通过多路径地址的节点列表

考虑以下Cyphers:选择在Cypher支架

MATCH (n{name: "John"})-[:Colleague]-(m) RETURN m; 

此查询查找的John(s)Colleague(s)。现在,另一个问题:

MATCH (n{name: "John"})-[:Friend]-()-[:Colleague]-(m) RETURN m; 

这一个发现的John(s)'Friend(s)Colleague(s)。现在是最后一个:

MATCH (n{name: "John"})-[:Colleague]-()-[:Friend]-(m) RETURN m; 

最后,人们发现的John(s)'Colleague(s)Friend(s)。我在找的是一个Cypher查询,它查找给定查询找到的所有节点的联合。

请注意,这只是一个例子。我在这里实际问到的是如何使用多条路径找到一组节点?例如:

MATCH (n{name: "John"}) 
    -[:Colleague]-/
    -[:Friend]-()-[:Colleague]-/
    -[:Colleague]-()-[:Friend]- 
    (m) RETURN m; 
+0

在查询语言中,UNION结合了多个查询的结果(加法),而JOIN采用多个查询(还原)的交集。如果我理解你是对的,你想加入,对吧? – Tezra

+0

@Tezra我在找UNION;所有节点都可以从n节点开始,并采用任何给定的路径。 – Mehran

回答

1

您可以在多个匹配中重复使用变量来引用同一个节点(JOIN模式)。实施例

MATCH (n{name: "John"})-[:Colleague]-(m) 
MATCH (n)-[:Friend]-()-[:Colleague]-(m) 
MATCH (n)-[:Colleague]-()-[:Friend]-(m) 
RETURN m; 

这里,“约翰”匹配一次,并用作每个匹配的开始,和m是加入每个匹配的有趣的节点。如果有多个“John”实例,则此查询将分别处理所有这些实例。如果所有的“约翰”都应该被视为同一个人,那么就不要重复使用n。

如果你想UNION代替JOIN,你可以收集他们这样

MATCH (n{name: "John"}) 
OPTIONAL MATCH (n)-[:Colleague]-(c) 
OPTIONAL MATCH (c)-[:Friend]-(fc) 
OPTIONAL MATCH (n)-[:Friend]-()-[:Colleague]-(fc) 
WITH c+collect(fc)+collect(cf) AS nodez 
UNWIND nodez AS m 
RETURN DISTINCT m; 
+0

我真的很喜欢你的第一个解决方案,如果工作!但是到目前为止,当测试它时,'(m)'没有加入。你确定如果你重用节点变量,它们可以连接在一起吗? – Mehran

+0

是的。你可以用一个更简单的模式来测试它。 'CREATE(a:TEST {id:1}) - [:HAS] - >(b:TEST {id:2}) - [:HAS] - >(c:TEST {id:3})CREATE(d: TEST {id:4}) - [:HAS] - >(b)CREATE(d) - [:HAS] - >(z:TEST {id:5})RETURN *' 然后 'MATCH(a: TEST {id:1}) - [:HAS] - >(b)MATCH(d:TEST {id:4}) - [:HAS] - >(b)RETURN *' (http://console.neo4j .org/r/a5qwio) – Tezra

+0

@Mehran第一个版本是,如果你只想要满足所有3(AKA JOIN)的节点。如果你想要所有满足任何模式的节点,你必须使用UNION或COLLECT()。 – Tezra

2

那么简单地使用UNION呢?试试看:

MATCH (n{name: "John"})-[:Colleague]-(m) 
RETURN m as node 

UNION 

MATCH (n{name: "John"})-[:Friend]-()-[:Colleague]-(m) 
RETURN m as node 

UNION 

MATCH (n{name: "John"})-[:Colleague]-()-[:Friend]-(m) 
RETURN m as node 
+0

这很棒,但如果我不想在这里完成我的查询呢?我的意思是我试图嵌入这个更大的查询,但它似乎UNION不能成为一个更大的查询的内部组成部分。是对的吗?如果你能告诉我如何找到具有类型关系的节点,这将是非常好的:与找到的(m)s同胞。我不是说为每个子查询添加' - [:兄弟] - >(o)'。我正在寻找一种方法来包含这个后期的一部分,与聚合的(m)的结果相关联。 – Mehran

+0

我相信UNION是不可能的。为了实现这个目标,使用@Tezra方法在[先前的回答](https://stackoverflow.com/a/44139032/6835358)(改编)中显示:'MATCH(n {name:“John”}) - [ (m) WITH n,collect(m)as z MATCH(n) - [:朋友] - () - [:同事] - (m) WITH n,z + collect(m)as z (m) MATCH(n) - [:同事] - () - [:朋友] - (m) WITH z + collect(m)AS m UNWIND m AS节点 MATCH(node) - [:Sibling] - > s) RETURN node,s'这会给你和UNION相同的结果,你可以继续查询。 –

3

在这种特殊情况下,可以使用多个关系类型可变长度的关系。但是,为了防止不好的路径(同事的同事,朋友的朋友,以及朋友),我们必须进行一些额外的筛选以确保路径中至少有一个同事关系。

MATCH (n{name: "John"})-[r:Colleague|Friend*1..2]-(m) 
WHERE 'Colleague' in [rel in r | type(rel)] 
RETURN m; 

另外,我强烈建议您使用节点上的标签,并在标签/名称组合使用一个索引,使您查找到您的约翰节点,而不必在检查每一个节点快,你的图。

这个查询不会像查询执行UNION那样高效,但只有索引查找和只有两次遍历,没有太多关系,它应该可以正常工作。

+0

尽管您的解决方案绝对有效并且工作正常(我甚至可能会将其用于解决我手边的问题)。但有没有办法实现任意路径?像UNION一样,但同时它可以成为更大查询的一部分。在我看来,UNION只能是查询的最外层,没有任何东西可以包装它。 – Mehran

+0

我为这个添加了一个单独的答案。 – InverseFalcon

1

为处理UNION查询添加单独的答案,同时保留处理联合结果的能力。

我们实际上有一个关于post-UNION processing的知识库文章,有几种不同的方法。

通过APOC程序,您可以在apoc.cypher.run()内执行UNION,并获取返回的联合结果并继续对其进行操作。

+0

对于那些没有APOC的人,你可以使用collect()像联合体(https://neo4j.com/blog/cypher-union-query-using-collect-clause/) – Tezra

1

这个简单的查询应该工作:

MATCH p=({name: "John"})-[:Friend*0..1]-()-[:Colleague]-()-[:Friend*0..1]-(m) 
WHERE LENGTH(p) <= 2 
RETURN m; 

它采用了可变长度模式*0..1使Friend关系可选。 WHERE子句筛选出长度超过2个关系的路径。