Neo4j Cypher - 查询部分固定路由和部分可变路由

时间:2016-07-21 18:26:40

标签: neo4j cypher

我们说我有一个图形网络,如下所示: Graph Network

我可以使用

之类的东西进行密码查询
MATCH (a:A)-[]->(b:B)-[]->(c:C)-[]-(d1:D),
(a)-[]->(b)-[]->(c)-[]-(d2:D),
(a)-[]->(b)-[]->(c)-[]-(d3:D),
(a)-[]->(b)-[]->(c)-[]-(d4:D),
WHERE d1.val = '1' AND d2.val = '2' AND d3.val ='3', d4.val = '4'
RETURN a, b, c, d1, d2, d3, d4

有没有办法简化这个查询,而不是一遍又一遍地显式重写关系,这是相同的。我试图找到具有我期望的所有D值的每个关系,这是一个很大的列表,所以可能IN子句是合适的。

编辑: 基于以下答案的示例数据

create (a1:A {name: 'A1'})
create (b1:B {name: 'B1'})
create (c1:C {name: 'C1'})
create (d1:D {name: 'D1', val: 1})
create (d2:D {name: 'D2', val: 2})
create (d3:D {name: 'D3', val: 3})
create (d4:D {name: 'D4', val: 4})
create (a1)-[:NEXT]->(b1)
create (b1)-[:NEXT]->(c1)
create (c1)-[:NEXT]->(d1)
create (c1)-[:NEXT]->(d2)
create (c1)-[:NEXT]->(d3)
create (c1)-[:NEXT]->(d4)
create (a2:A {name: 'A2'})
create (b2:B {name: 'B2'})
create (c2:C {name: 'C2'})
create (a2)-[:NEXT]->(b2)
create (b2)-[:NEXT]->(c2)
create (c2)-[:NEXT]->(d1)
create (c2)-[:NEXT]->(d2)
create (a3:A {name: 'A3'})
create (b3:B {name: 'B3'})
create (c3:C {name: 'C3'})
create (a3)-[:NEXT]->(b3)
create (b3)-[:NEXT]->(c3)
create (c3)-[:NEXT]->(d1)
create (c3)-[:NEXT]->(d2)
create (c3)-[:NEXT]->(d3)
create (c3)-[:NEXT]->(d4)
return *

因此,查询应该会生成A1-->B1-->C1-->D1,D2,D3,D4A3-->B3-->C3-->D1,D2,D3,D4 由于A2-->B2--C2仅与D1,D2而非D3,D4相关联,因此不应在结果中。

3 个答案:

答案 0 :(得分:2)

如果每个D节点都有唯一的val属性(如果有的话),那么这应该有效:

WITH [1,2,3,4] AS desired

MATCH (a:A)-->(b:B)-->(c:C)-->(d:D)
WHERE d.val IN desired
WITH a, b, c, COLLECT(DISTINCT d) AS ds
WHERE SIZE(ds) = SIZE(desired)
RETURN a, b, c, ds

每个匹配的ABC组合的结果以及D个节点的集合都会有一行。

答案 1 :(得分:2)

路径的开头始终相同,因此您不需要重复它。然后,根据值列表,您要检查是否可以为每个值找到D:它可能是all的作业。

混合所有这些,我们得到:

MATCH (a:A)-->(b:B)-->(c:C)-->(d:D)
WHERE d.val IN {values}
WITH a, b, c, collect(d) AS dList
WHERE all(value IN values WHERE any(d IN dList WHERE d.val = value))
RETURN a, d, c, dList

但是,如果 n 是值的数量,那么由于第二个WHERE,这是一个O(n ^ 2)算法。

让我们在收集节点本身的同时收集节点的值,以避免双循环并将其转换为O(n)算法:

MATCH (a:A)-->(b:B)-->(c:C)-->(d:D)
WHERE d.val IN {values}
WITH a, b, c, collect(d) AS dList, collect(DISTINCT d.val) AS dValues
WHERE all(value IN values WHERE value in dValues)
RETURN a, d, c, dList

假设作为参数传递的值列表仅包含不同的值,我们甚至可以通过简单地比较输入列表的大小和找到的不同值来将其更改为O(1)算法:

MATCH (a:A)-->(b:B)-->(c:C)-->(d:D)
WHERE d.val IN {values}
WITH a, b, c, collect(d) AS dList, collect(DISTINCT d.val) AS dValues
WHERE size({values}) = size(dValues)
RETURN a, d, c, dList

由于dValues ⊂ values,如果2套具有相同的尺寸,则它们相等。

如果D.val全局唯一,或者对于连接到单个D的所有C节点至少是唯一的,则可以进一步简化:

MATCH (a:A)-->(b:B)-->(c:C)-->(d:D)
WHERE d.val IN {values}
WITH a, b, c, collect(d) AS dList
WHERE size({values}) = size(dList)
RETURN a, d, c, dList

如果值是全局唯一的,则使用unicity约束查询会更快,因为它还会索引值:

CREATE CONSTRAINT ON (d:D) ASSERT d.val IS UNIQUE

答案 2 :(得分:1)

假设以下数据集......

create (a:A {name: 'A'})
create (b:B {name: 'B'})
create (c:C {name: 'C'})
create (d1:D {name: 'D1', val: 1})
create (d2:D {name: 'D2', val: 2})
create (d3:D {name: 'D3', val: 3})
create (d4:D {name: 'D4', val: 4})
create (a)-[:NEXT]->(b)
create (b)-[:NEXT]->(c)
create (c)-[:NEXT]->(d1)
create (c)-[:NEXT]->(d2)
create (c)-[:NEXT]->(d3)
create (c)-[:NEXT]->(d4)
return *

您可以执行类似这样的查询,以匹配特定值范围内的所有特定D节点。

match (a:A)-->(b:B)-->(c:C)-->(d:D)
where d.val in range(1,4)
return *

以下是基于您更新的问题的更新查询。我收集了每个D节点链的A,B,C值。

match (a:A)-->(b:B)-->(c:C)-->(d:D)
where d.val in range(1,4)
with a, b, c, d
order by a.name, b.name, c.name, d.name
return a, b, c, collect(d) as d
order by a.name, b.name, c.name