Neo4j匹配与集合中所有节点相关的节点

时间:2015-10-08 14:34:37

标签: neo4j cypher

我有一个标签图,它们彼此相关。我的目标是创建一个Cypher查询,它将通过1或2个跃点返回与输入标记数组相关的所有标记。

我提出了一个查询,该查询无法按预期运行。

MATCH (t:Tag)
WHERE t.name IN ["A", "B", "C"]
WITH t
MATCH (a:Tag)-[:RELATED*1..2]-(t)
RETURN DISTINCT a;

此查询首先查找节点ABC,然后搜索与AB 相关的标记或 C通过1个节点或更少。

我想要做的是找到与所有三个节点相关的标签(AB C)。

我知道我可以连接MATCHWITH语句,并执行以下操作:

MATCH (t:Tag)-[:RELATED*1..2]-(a:Tag)
WHERE t.name="A"

WITH DISTINCT a
MATCH (t:Tag)-[:RELATED*1..2]-(a)
WHERE t.name="B"

WITH DISTINCT a
MATCH (t:Tag)-[:RELATED*1..2]-(a)
WHERE t.name="C"
...
RETURN DISTINCT a;

但是当输入标签的数量增加时(在这种情况下只有3个输入标签:ABC),它的运行速度非常缓慢。

那么有没有办法在一个查询中创建它,类似于我的第一次尝试?

3 个答案:

答案 0 :(得分:5)

这是一个只需要一个MATCH子句的解决方案。

MATCH (t:Tag)-[:RELATED*..2]-(other:Tag)
WHERE t.name IN ["A", "B", "C"]
WITH t, COLLECT(DISTINCT other) AS others
WITH COLLECT(others) AS coll
RETURN FILTER(x IN coll[0] WHERE ALL(y IN coll[1..] WHERE x IN y)) AS res;
  • 查询会查找与您的每个指定代码(other)“相关”(最多2步)的所有代码(t)。
  • 然后使用聚合为每个other收集不同的 t节点。在此示例中,我们最终得到3个others个集合 - 每个t有1个集合。需要注意的重要一点是查询结果是每个 others集合的交集。
  • 然后,它会将所有others个集合收集到一个coll集合中。
  • 最后,由于结果集是每个others集合的交集,因此查询将遍历第一个others集合中的节点,并提取其余others中的节点。集合。并且,由于每个others集合已包含不同的节点,因此结果还必须具有不同的节点。

此外,如果您有很多标签,可以通过以下方式加快上述查询:

  1. Creating an index(或uniqueness constraint,会自动为您创建索引):Tag(name),然后
  2. 在查询中指定使用该索引 - 在MATCHWHERE子句之间插入以下子句。目前,Cypher引擎不会自动使用此特定查询的索引。

    USING INDEX t:Tag(name)
    

答案 1 :(得分:1)

这是另一种选择:

MATCH shortestPath((t:Tag)<-[:RELATED*1..2]-(source:Tag)) //make sure there are no duplicate paths 
WHERE source.name IN ["A","B","C"] AND NOT source.name = t.name //shortest path for identical node would throw an exception
WITH COLLECT(t) as tags //all tags that were reachable, with duplicates for reachable from multiple tags
UNWIND tags as tag //for each tag
WITH tag, tags //using with as match would be a drastic slowdown
WHERE size(filter(t IN tags WHERE ID(t) = ID(tag))) = 3 //if it is connected to all three, it must have been matched three times
RETURN DISTINCT m //since any match will still be in there 3 (or n) times

首先匹配所有可访问的标记。如果使用shortestPath,则从长度为n的列表中的所有标记可到达的所有标记必须已匹配n次。如果您按照该标准进行过滤(当前n次),则可以使用不同的标记来检索所需的标记。

答案 2 :(得分:0)

这个怎么样:

MATCH (t:Tag)-[:RELATED*1..2]-(other:Tag)
WHERE t.name IN ["A", "B", "C"] 
WITH t, collect(other.name) as others
WHERE ALL(x in ["A","B","C"] WHERE x in others)
RETURN t

诀窍是将t的所有相关节点放入集合(其他)并使用ALL谓词来确保所有A,B和C都是其中的一部分。