【问题标题】:Cypher query to find shortest partial paths and aggregate the result密码查询以查找最短的部分路径并聚合结果
【发布时间】:2017-10-05 01:33:31
【问题描述】:

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

例子:

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 个节点,因为人员将根据某个值进行过滤。

【问题讨论】:

  • 这些轨迹(路径)是否单独存储在图中?例如,您是否为 person1 创建了两个节点? (因为您的第一个查询返回 person1,我相信是这种情况。)
  • 每个人都是一个有多个边的节点。
  • 您是否有固定(少量)的检查点,或者这也会发生变化?
  • 如果检查点很多,这很重要,最好使用通用标签(例如:Checkpoint)和属性(例如step)。另外,我在您的示例中添加了一个数字并进行了一些更改——请仔细检查。
  • @JeffNewbie 在您提供的数据库中,每个人都有 1 个优势。 (而且我无法理解架构)如果您将架构更改为使用一组检查点(由一些 :Next 关系连接)并且每个人都作为与他们所做的每个检查点的:Reached 关系,您的查询可能只是MATCH (person:person) OPTIONAL MATCH (person)-[:REACHED]->(cp:chkpt) RETURN person, COUNT(cp) as checkpoints ORDER BY checkpoints(根据需要过滤。不太确定您真正想要的最终结果是什么)这是我的意思的example

标签: neo4j cypher


【解决方案1】:

但是,我只想返回 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.) 如果可能,您可以考虑查看您的数据模型并将人员和检查点存储为单个节点并添加它们之间的路径。这是一种更像图的表示形式,应该有助于制定有效的查询。

【讨论】:

  • 感谢您的回复,我已经更新了问题。 (1) 我会尝试 (3) 由于我正在寻找到达的最早检查点,因此人员 1 被指示为未到达 chkpt1。对于第 2 个人,我更新了问题以澄清。我正在寻找确定有多少人通过了所有 chkpt,如果他们没有,那么他们达到的最低 ckhpt。
猜你喜欢
  • 2013-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-18
  • 1970-01-01
相关资源
最近更新 更多