Cypher查询neo4j以获得所需的遍历

时间:2015-09-21 19:25:38

标签: neo4j cypher

我正在修改问题,以便可以轻松测试

用于测试的图表

enter image description here

绿色节点是组织,蓝色节点是人。以下是创建此图表的脚本:

CREATE (A:Organization {PRID:'A', Name:'Organization-A'})
CREATE (B:Organization {PRID:'B', Name:'Organization-B'})
CREATE (C:Organization {PRID:'C', Name:'Organization-C'})
CREATE (D:Organization {PRID:'D', Name:'Organization-D'})
CREATE (E:Organization {PRID:'E', Name:'Organization-E'})
CREATE (F:Organization {PRID:'F', Name:'Organization-F'})
CREATE (G:Organization {PRID:'G', Name:'Organization-G'})
CREATE (H:Organization {PRID:'H', Name:'Organization-G'})
CREATE (I:Organization {PRID:'I', Name:'Organization-I'})


CREATE (P1:Person {PRID:'P1', Name:'Person-P1'})
CREATE (P2:Person {PRID:'P2', Name:'Person-P2'})
CREATE (P3:Person {PRID:'P3', Name:'Person-P3'})
CREATE (P4:Person {PRID:'P4', Name:'Person-P4'})
CREATE (P5:Person {PRID:'P5', Name:'Person-P5'})
CREATE (P6:Person {PRID:'P6', Name:'Person-P6'})

CREATE
  (B)-[:CONTROL]->(A),
  (C)-[:CONTROL]->(A),
  (D)-[:CONTROL]->(C),
  (E)-[:CONTROL]->(C),
  (G)-[:CONTROL]->(F),
  (H)-[:CONTROL]->(F),

  (D)-[:EMPLOYS]->(P1),
  (P1)-[:SPOUSE]->(P2),
  (P2)-[:CONSULTS]->(E),

  (B)-[:EMPLOYS]->(P3),
  (P3)-[:SPOUSE]->(P4),
  (P4)-[:CONSULTS]->(I),

  (H)-[:EMPLOYS]->(P5),
  (P5)-[:SPOUSE]->(P6)
;

我正在尝试编写一个需要完成以下操作的密码查询:

a)以PRID ='C'的节点开始。

b)路径p1 =所有连接到起始节点的节点,关系类型为CONTROL(递归) - 无论方向如何

c)路径p2 =可选地匹配以下关系模式
              (x1) - [:EMPLOYS] - >() - [:SPOUSE] - >() - [:CONSULTS] - >(x2)
其中(x1)和(x2)是路径p1中的节点 - 在步骤(b)中找到。

返回p1和p2


直到现在已经尝试了以下三个查询(在Brian的帮助下)

Query1:
MATCH p1=(x:Organization {PRID: 'C'})-[r:CONTROL*]-(y)
OPTIONAL MATCH p2=(node1)-[:EMPLOYS]->()-[:SPOUSE]->()-[:CONSULTS]->(node2)
WHERE node1 in nodes(p1) and node2 in nodes(p1)
RETURN p1,p2;

Quesry2:
MATCH p1=(x:Organization {PRID: 'C'})-[r:CONTROL*]-(y)
WITH p1, nodes(p1) AS p1_nodes
UNWIND p1_nodes AS node1
UNWIND p1_nodes AS node2
WITH p1, node1, node2
OPTIONAL MATCH p2=(node1)-[:EMPLOYS]->()-[:SPOUSE]->()-[:CONSULTS]->(node2)    
WHERE p2 IS NOT NULL
RETURN p1, p2;

Query3:
MATCH p1=(x:Organization {PRID: 'C'})-[r:CONTROL*]-(y)
WITH p1, EXTRACT(node IN nodes(p1) | ID(node)) AS p1_node_ids
UNWIND p1_node_ids AS id1
UNWIND p1_node_ids AS id2
OPTIONAL MATCH p2=(node1)-[:EMPLOYS]->()-[:SPOUSE]->()-[:CONSULTS]->(node2)
WHERE ID(node1) = id1 AND ID(node2) = id2 AND p2 IS NOT NULL
RETURN p1, p2;

我期望的是回到带有节点A,B,C,D,E,P1,P2的子图与关系,但是这三个只给我A,B,C,D,E关系(只是p1,没有p2)

我们尝试过的一些查询可以处理一些锚节点,但不能处理第一层次结构中的任何节点

Query-4
MATCH p1=(x:Organization {PRID: 'C'})-[r:CONTROL*]-(y)
WITH collect({path: p1, node: y}) AS paths_and_nodes
UNWIND paths_and_nodes AS paths_and_node1
UNWIND paths_and_nodes AS paths_and_node2
WITH
  paths_and_node1.node AS node1,
  paths_and_node2.node AS node2,
  paths_and_node1.path AS path1,
  paths_and_node2.path AS path2
OPTIONAL MATCH p2=(node1)-[:EMPLOYS]->()-[:SPOUSE]->()-[:CONSULTS]->(node2)
RETURN path1, path2, p2, node1, node2

这个用x指定为A,B或C.但是如果x指向D或E则不起作用

Query 5
MATCH
  p1=(org1)-[:CONTROL*]-(x:Organization {PRID: 'C'})-[:CONTROL*]-(org2)
OPTIONAL MATCH p2=(org1)-[:EMPLOYS]->()-[:SPOUSE]->()-[:CONSULTS]->(org2)
RETURN p1, p2, org1, org2

这个用x指定为C,D或E.但是如果x指向A或B则不起作用

一想法 - 如果我们将查询作为

MATCH p1=(x:Organization {PRID: 'E'})-[r:CONTROL*]-(y)
OPTIONAL MATCH p2=(node1)-[:EMPLOYS]->()-[:SPOUSE]->()-[:CONSULTS]->(node2)
WHERE node1.PRID in ['A','B','C','D','E'] AND 
      node2.PRID in ['A','B','C','D','E']
RETURN p1,p2;

然后它显然工作正常。所以我们不能以某种方式使用COLLECT等创建这个数组并将其传递给下一个查询。问题似乎是 - 如果在第一场比赛后我使用了WITH P1,COLLECT(y.PRID)AS p1_prids,那么p1_prids不是['A','B','C',' D','E']而是一个多行集合,每个集合只有一个元素

我可以使其始终如一地工作的一种方式是

MATCH (x:Organization {PRID: 'C'})-[r:CONTROL*0..]-(y)
WITH COLLECT (y.PRID) AS p1_prids
MATCH p1=(x:Organization {PRID: 'C'})-[r:CONTROL*0..]-(y)
WITH p1,p1_prids
OPTIONAL MATCH p2=(node1)-[:EMPLOYS]->()-[:SPOUSE]->()-[:CONSULTS]->(node2)
WHERE node1.PRID in p1_prids AND  node2.PRID in p1_prids

但我认为这是非常不优雅和性能的噩梦,因为它会进行两次查询 - 所以仍然在寻找解决方案......

我在这个查询中做错了什么?
是否有更好的方法来解决这个问题

提前致谢...

2 个答案:

答案 0 :(得分:1)

好的,让我重新开始为您的新数据集添加一个不同的答案(顺便说一句,顺便说一句,这真的很有帮助!)

我没有意识到的问题是,您希望一起匹配的节点将位于p1路径的不同结果中,因为它们位于起始节点的任一侧。所以你可以这样做:

MATCH p1=(x:Organization {PRID: 'C'})-[r:CONTROL*]-(y)
WITH collect({path: p1, node: y}) AS paths_and_nodes
UNWIND paths_and_nodes AS paths_and_node1
UNWIND paths_and_nodes AS paths_and_node2
WITH
  paths_and_node1.node AS node1,
  paths_and_node2.node AS node2,
  paths_and_node1.path AS path1,
  paths_and_node2.path AS path2
MATCH p2=(node1)-[:EMPLOYS]->()-[:SPOUSE]->()-[:CONSULTS]->(node2)
RETURN path1, path2, p2, node1, node2

或类似的东西更简单:

MATCH
  p1=(org1)-[:CONTROL*]-(x:Organization {PRID: 'C'})-[:CONTROL*]-(org2),
  p2=(org1)-[:EMPLOYS]->()-[:SPOUSE]->()-[:CONSULTS]->(org2)
RETURN p1, p2, org1, org2

修改 所以我想我看到了问题。我没想过从任何Organization节点开始。我很确定第二个查询永远不会起作用,因为Cypher永远不会在路径中两次击中同一个节点。因此,查看第一个查询的原因是它不使用D和E是因为默认的[*]变量关系定义是针对一个或多个跃点。如果我们让它为零或更多跳跃,那么它似乎有效:

MATCH p1=(x:Organization {PRID: 'C'})-[r:CONTROL*0..]-(y)
WITH collect({path: p1, node: y}) AS paths_and_nodes
UNWIND paths_and_nodes AS paths_and_node1
UNWIND paths_and_nodes AS paths_and_node2
WITH
  paths_and_node1.node AS node1,
  paths_and_node2.node AS node2,
  paths_and_node1.path AS path1,
  paths_and_node2.path AS path2
OPTIONAL MATCH p2=(node1)-[:EMPLOYS]->()-[:SPOUSE]->()-[:CONSULTS]->(node2)
RETURN path1, path2, p2, node1, node2

怎么样?

答案 1 :(得分:0)

让我试一试! ;)

首先,您可以像这样简化第一个MATCH / WHERE组合:

MATCH p1=(x:Organization {PID: '27762230'})-[r:`10006`|`10010`*]-(y) 

所以,让我们接受并尝试做你想做的事情:

MATCH p1=(x:Organization {PID: '27762230'})-[r:`10006`|`10010`*]-(y) 
WITH p1, nodes(p1) AS p1_nodes
UNWIND p1_nodes AS node1
UNWIND p1_nodes AS node2
WITH p1, node1, node2
OPTIONAL MATCH p2=(node1)-[:`10004`]->()-[:`10051`]->()-[:`10052`]->(node2)
WHERE p2 IS NOT NULL
RETURN p1, p2

当您调用nodes(path)时,您获得的对象不是节点属性Map的节点,也可能是MATCH p1=(x:Organization {PID: '27762230'})-[r:`10006`|`10010`*]-(y) WITH p1, EXTRACT(node IN nodes(p1) | ID(node)) AS p1_node_ids UNWIND p1_node_ids AS id1 UNWIND p1_node_ids AS id2 OPTIONAL MATCH p2=(node1)-[:`10004`]->()-[:`10051`]->()-[:`10052`]->(node2) WHERE ID(node1) = id1 AND ID(node2) = id2 AND p2 IS NOT NULL RETURN p1, p2 。如果是这样,我们应该能够通过ID进行匹配:

RegisterView()