用于 Neo4j 的 Cypher 查询以获得所需的遍历
Posted
技术标签:
【中文标题】用于 Neo4j 的 Cypher 查询以获得所需的遍历【英文标题】:Cypher Query for neo4j to get the desired traversal 【发布时间】:2015-09-21 19:25:37 【问题描述】:我正在修改问题以便可以轻松测试
用于测试的图表
绿色节点是组织,蓝色节点是个人。这是创建此图表的脚本:
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
但我认为这是非常不优雅和性能噩梦,因为它会查询两次 - 所以仍在寻找解决方案......
我在这个查询中做错了什么? 有没有更好的方法来解决这个问题
提前致谢...
【问题讨论】:
【参考方案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
怎么样?
【讨论】:
【参考方案2】:让我试一试! ;)
所以首先你可以像这样简化你的第一个 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
s 那么多。如果是这样,我们应该能够通过 ID 进行匹配:
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
【讨论】:
感谢您的建议,但它对我不起作用。有几件事(a)它在 WHERE 处给出了一个语法错误——我认为你放它是为了避免路径 p2 循环回同一个节点——这实际上不是我需要的——所以我删除了它。然而,在删除它之后 - 我没有得到任何结果。然后我将第二个 MATCH 更改为一个 OPTINAL MATCH - 之后它返回子图 p1 但不返回 p2 - 即使在我拥有的数据中我确实有满足该条件的数据...... 我在测试中注意到的另一件事 - 所以在这个路径 p2 的查询中,我们试图将 p2 的起始节点和结束节点限制在 p1 中找到的节点集 - 我观察到的是,如果您一次只限制一个 - 也就是说,如果我们将 node1 更改为 xxx 或我们将 node2 更改为 xxx,则在您上面的查询中,如果我们将 node1 更改为 xxx,它会在结果中显示 p1 和 p2 ...但这显然不是我们想要什么 - 因为我们的要求是将起始节点和结束节点都限制在 p1 中找到的节点集 ... 关于WHERE
和MATCH
的优点。我已经编辑以反映这些。我不太清楚为什么OPTIONAL MATCH
不起作用。我已经编辑了一些建议
再次感谢您的建议布赖恩,不幸的是仍然不行,我正在使用一个简单的 Cypher 脚本编辑上面的帖子来测试这个查询,以便您/某人可以轻松尝试...
感谢您的所有帮助,我尝试了您提供的查询 - 它们适用于某些条件但并非适用于所有条件,因为很难将查询放入 cmets 我正在使用结果更新我的问题您在上一个答案中提供的查询...以上是关于用于 Neo4j 的 Cypher 查询以获得所需的遍历的主要内容,如果未能解决你的问题,请参考以下文章