Cypher查询以查找最短的部分路径并聚合结果

时间:2017-10-05 01:33:31

标签: neo4j cypher

我正在尝试找到每个人在节点之间遍历的最小检查点。每个人都可以遍历多条路径。

示例:

CREATE
  (:person {id: 0}),
  (:person {id: 1})-[:rel1]->(:chkpt1 {id: '1'})-[:rel2]->(:chkpt2 {id: '2'}),

  (:person {id: 2})-[:rel1]->(:chkpt1 {id: '1_1'}),
  (:person {id: 2})-[:rel1]->(:chkpt1 {id: '1_2'})-[:rel2]->(:chkpt2 {id: '2_1'}),
  (:person {id: 2})-[:rel1]->(:chkpt1 {id: '1_3'})-[:rel2]->(:chkpt2 {id: '2_2'})-[:rel3]->(:chkpt3 {id: '3_1'}),

  (:person {id: 3})-[:rel1]->(:chkpt1 {id: '1_4'})-[:rel2]->(:chkpt2 {id: '2_3'})-[:rel3]->(:chkpt3 {id: '3_2'}),
  (:person {id: 3})-[:rel1]->(:chkpt1 {id: '1_5'})-[:rel2]->(:chkpt2 {id: '2_4'})-[:rel3]->(:chkpt3 {id: '3_3'}),
  (:person {id: 3})-[:rel1]->(:chkpt1 {id: '1_6'})-[:rel2]->(:chkpt2 {id: '2_5'})-[:rel3]->(:chkpt3 {id: '3_4'})

目前,我正在使用OPTIONAL MATCH子句并运行多个查询,如下所示:

MATCH (p:person)
OPTIONAL MATCH (p)-[:rel1]-(cp1:chkpt1)
WITH p, cp1
WHERE cp1 IS NULL
RETURN p.id

返回:person0

然后我运行一个单独的查询来查找没有进入下一个检查点的所有人。

MATCH (p:person)-[:rel1]-(cp1:chkpt1)
OPTIONAL MATCH (cp1)-[:rel2]-(cp2:chkpt2)
WITH p, cp1, cp2
WHERE cp2 IS NULL
RETURN DISTINCT p.id, cp1.id

返回:person2

同样适用于下一个检查点。

MATCH (p:person)-[:rel1]-(cp1:chkpt1)-[:rel2]-(cp2:chkpt2)
OPTIONAL MATCH (cp2)-[:rel3]-(cp3:chkpt3)
WITH p, cp1, cp2, cp3
WHERE cp3 IS NULL
RETURN DISTINCT p.id, cp1.id, cp2.id

返回:person1和person2

我想只返回person1,因为person2错过了之前的遍历。

MATCH (p:person)-[:rel1]-(cp1:chkpt1)-[:rel2]-(cp2:chkpt2)-[:rel3]-(cp3:chkpt3)
RETURN DISTINCT p.id, cp1.id, cp2.id

返回:person2和person3

但是,我想只返回person3,因为person2没有进入chkpt3和chkpt2。

我不需要包括那些已经被排除在外的人,因为他们没有进入另一次遍历的前一个检查站。

示例:

  • person1应该只显示他们没有进入chkpt1。
  • person2应该只显示他们没有进入chkpt3。
  • person3在chkpt3中显示,因为他们完成了到最终chkpt3的所有路径。

我想总结那些进入某个检查站的人数。由于可能有多人进入最短的检查站。

我还尝试将所有查询与多个OPTIONAL MATCH子句组合在一起,但当节点数量增加时,这种情况会慢下来。

总节点数将达到100,000到100万。实际遍历将只涉及1000个节点,因为将根据某些值过滤人员。

1 个答案:

答案 0 :(得分:0)

  

但是,我想只返回person3,因为person2没有进入chkpt3和chkpt2。

这个查询怎么样?它计算一个人参与的遍历次数,并检查他们是否在所有遍历中都进入了检查点3。

MATCH (p:person)-[r]-()
WITH p, count(r) AS allTraversals
MATCH (p)-[:rel1]-(cp1:chkpt1)-[:rel2]-(cp2:chkpt2)-[:rel3]-(cp3:chkpt3)
WITH p, allTraversals, count(cp3) AS cp3s
WHERE allTraversals = cp3s
RETURN p

(注意:这不适用于person0。)

另外,有几点意见:

(1。)您可以使用WHERE NOT <pattern>结构以更简洁的方式制定负面条件。

MATCH (p:person)
WHERE NOT (p:person)-[:rel1]->(:chkpt1)
RETURN p

(2。)如果可能,您可以考虑检查数据模型并将人员和检查点存储为单个节点,并在它们之间添加路径。这是一个更像图形的表示,应该有助于制定有效的查询。