apoc.neighbors.byhop

详细信息

语法

apoc.neighbors.byhop(node [, relTypes, distance ]) :: (nodes)

描述

返回由给定 RELATIONSHIP(关系)类型在指定距离内连接的所有 NODE(节点)值。返回 LIST<NODE>(节点列表)值,其中 NODE 值的每个 PATH(路径)代表 LIST<NODE> 值的一行。

输入参数

名称

类型

描述

节点

NODE

算法的起始节点。

关系类型

STRING

要追踪的关系类型列表。关系类型使用 APOC 的关系方向模式语法表示;[<]RELATIONSHIP_TYPE1[>]|[<]RELATIONSHIP_TYPE2[>]|…​。默认值为:``。

距离

INTEGER(整数)

要跳跃的最大步数。默认值为:1

返回参数

名称

类型

描述

节点

LIST<NODE>

按不同跳数距离排列的邻近节点列表。

使用示例

本节中的示例基于以下示例图

MERGE (mark:Person {name: "Mark"})
MERGE (praveena:Person {name: "Praveena"})
MERGE (joe:Person {name: "Joe"})
MERGE (lju:Person {name: "Lju"})
MERGE (michael:Person {name: "Michael"})
MERGE (emil:Person {name: "Emil"})
MERGE (ryan:Person {name: "Ryan"})

MERGE (ryan)-[:FOLLOWS]->(joe)
MERGE (joe)-[:FOLLOWS]->(mark)
MERGE (mark)-[:FOLLOWS]->(emil)
MERGE (michael)-[:KNOWS]-(emil)
MERGE (michael)-[:KNOWS]-(lju)
MERGE (michael)-[:KNOWS]-(praveena)
MERGE (emil)-[:FOLLOWS]->(joe)
MERGE (praveena)-[:FOLLOWS]->(joe)

apoc.neighbors.byhop 过程用于计算节点在多个跳数下的邻域。

以下代码返回 Emil KNOWS(认识)的人,最多 2 跳。

MATCH (p:Person {name: "Emil"})
CALL apoc.neighbors.byhop(p, "KNOWS", 2)
YIELD nodes
RETURN nodes
结果
节点

[(:Person {name: "Michael"})]

[(:Person {name: "Praveena"}), (:Person {name: "Lju"})]

从这些结果中我们可以看出,在第 1 层,Emil KNOWS Michael;在第 2 层,Emil KNOWS Lju 和 Praveena。以下图表模式描述了 Emil 与不同人的认识关系:

第 1 层
  • (emil)-[:KNOWS]-(michael)

第 2 层
  • (emil)-[:KNOWS]-(michael)-[:KNOWS]-(lju)

  • (emil)-[:KNOWS]-(michael)-[:KNOWS]-(praveena)

在搜索邻域时,我们还可以使用多种关系类型。

假设除了找到 Emil 认识的人之外,我们还想找到关注他的人。我们可以通过使用 < 表示传入关系,或使用 > 表示传出关系,来指定关系类型的方向。因此,要找到关注 Emil 的人,我们将使用 <FOLLOWS

以下代码返回 Emil KNOWS(认识)的人以及那些与他有 FOLLOWS(关注)关系的人,最多 3 跳。

MATCH (p:Person {name: "Emil"})
CALL apoc.neighbors.byhop(p, "KNOWS|<FOLLOWS", 3)
YIELD nodes
RETURN nodes
结果
节点

[(:Person {name: "Mark"}), (:Person {name: "Michael"})]

[(:Person {name: "Praveena"}), (:Person {name: "Joe"}), (:Person {name: "Lju"})]

[(:Person {name: "Ryan"})]

这次我们得到了更多的结果。Mark 在 Emil 的第 1 层邻域中,Joe 在他的第 2 层邻域中,而 Ryan 在他的第 3 层邻域中。

以下图表模式描述了 Emil 与不同人的关系:

第 1 层
  • (emil)-[:KNOWS]-(michael)

  • (mark)-[:FOLLOWS]→(emil)

第 2 层
  • (emil)-[:KNOWS]-(michael)-[:KNOWS]-(lju)

  • (emil)-[:KNOWS]-(michael)-[:KNOWS]-(praveena)

  • (joe)-[:FOLLOWS]→(mark)-[:FOLLOWS]→(emil)

第 3 层
  • (ryan)-[:FOLLOWS]→(joe)-[:FOLLOWS]→(mark)-[:FOLLOWS]→(emil)

并且,正如 apoc.neighbors.athop 过程一样,我们也可以只返回每一跳的邻域大小。

以下代码返回 Emil 在 3 跳距离内 KNOWS 的人数以及关注他的人数

MATCH (p:Person {name: "Emil"})
CALL apoc.neighbors.byhop.count(p, "KNOWS|<FOLLOWS", 3)
YIELD value
RETURN value
结果

[2, 3, 1]

正如预期的那样,我们在第 1 层级得到 2,第 2 层级得到 3,第 3 层级得到 1。

我们甚至可以将该数字列表转换为映射 (map),其中键为跳数,值为邻域大小。以下查询展示了如何使用 apoc.map.fromLists 函数来实现这一点。

MATCH (p:Person {name: "Emil"})
CALL apoc.neighbors.byhop.count(p, "KNOWS|<FOLLOWS", 3)
YIELD value
RETURN apoc.map.fromLists(
         [value in range(1, size(value)) | toString(value)],
         value) AS value
结果

{1: 2, 2: 3, 3: 1}

如果我们不关心邻域中有哪些节点,而只想知道数量,也可以做到。请参阅 apoc.neighbors.byhop.count