如何从多个起始节点匹配到每行特定类型的最近 n 个节点?

How do I match from multiple starting nodes to the closest n nodes of a particular type per row?

我正在寻找一种方法来进行广度优先搜索或从某些起始节点到一种节点(无论是通过标签还是通过 属性)的最短路径,然后停止当我找到第一个匹配项(或 n 个匹配项,如果我可以将其作为参数)。

我想知道 Cypher 本身是否存在解决方案,如果没有,是否有现有的程序(来自 APOC 或其他来源)来执行此操作,如果没有,我将如何实现(也许使用遍历框架?)

neo4j 本身和 APOC 库中的 shortestPath() 算法在您知道起始节点和结束节点时,或者如果您想要基于所有可能的起始节点或结束节点进行匹配时,效果最佳。

但是当我们不明确知道我们的端节点时,我们只想找到第一个匹配某些谓词或标签的节点(或节点,如果我们允许我们要查找的数字被参数化),那些程序似乎不太有效。

例如,假设我有 :Persons 的社交图,他们之间有 [:Knows] 关系,并且 :Persons 和 :City 之间有 [:LivesIn] 关系。最后,:Persons 还被标记为他们的职业(所以 :Person who is a doctor 也被标记为 :Doctor)

使用此示例图,对于给定的 :City,对于该城市中的所有 :Persons,我想找到每个 :Person 遵循 [:Knows] 关系与 :Doctor 的最短路径。作为输出,我想看到每个 :Person,他们最近的 :Doctor,到那个 :Doctor 的 [:Knows] 跳数,按跳数降序排列。

如果我使用的是 neo4j 最短路径,我的查询可能如下所示:

MATCH (c:City)<-[:LivesIn]-(p:Person)
WHERE c.name = "San Diego"
WITH p
MATCH path = shortestPath( (p)-[:Knows*]-(d:Doctor) )
...

在这一点上,我们有行将图中的每个人与每个医生配对,以及他们之间的最短路径。至于下一步要做什么,我可能会收集所有路径,这样我们就返回到每个 :Person 一行,然后按路径长度升序对所有集合进行排序,然后为每个用户取路径集合的头部,然后输出 :Person , 他们最近的 :Doctor, 以及他们之间的跳数。

那根本没有效率。我想要到最近的 :Doctor 的最短路径,并在找到第一个 :Doctor 节点后停止搜索。

如果存在简单的解决方案,我还想知道是否支持其他选项(基于谓词和属性进行查找,而不仅仅是标签),以及我希望它查找的匹配项数量是否可以参数化(例如,如果我想找到最近的 2 位医生)。

为什么不在 return 语句中使用 LIMIT 1?

APOC 已经相当成熟了,现在对这些需求都有了答案。

使用apoc.path.expandConfig()(和其他路径扩展程序)现在可以扩展到具有特定标签的节点,并在达到给定限制后停止进一步扩展(例如请求每个人最近的 n 位医生).

使用 apoc.cypher.run(),现在可以使用 LIMIT 执行 Cypher 查询,并且该限制将应用于每行的结果,而不是限制所有行。这适用于更复杂的情况,其中仅节点标签和关系类型不足以描述遍历或所需的节点,例如需要 属性 评估时。

这两种方法都在 Neo4j knowledge base entry 中进行了演示。