邻居函数
邻域搜索过程能够根据特定的关系类型和跳数快速发现周围的节点。
可用过程
下表描述了可用的过程:
| 限定名称 | 类型 |
|---|---|
apoc.neighbors.athop |
|
apoc.neighbors.byhop |
|
apoc.neighbors.tohop |
|
关系过滤器
每个邻域搜索过程的第 2 个参数都是一个关系过滤器。关系过滤器是由 | 分隔的关系类型列表,使用以下语法
语法: [<]RELATIONSHIP_TYPE1[>]|[<]RELATIONSHIP_TYPE2[>]|…
| input | type | 方向 |
|---|---|---|
|
|
OUTGOING (出站) |
|
|
INCOMING (入站) |
|
|
BOTH (双向) |
|
|
OUTGOING (出站) |
|
|
INCOMING (入站) |
|
关系过滤器对空格敏感,因此如果您没有看到预期的结果,请检查是否存在尾随空格(并将其删除!)。 |
示例
本节中的示例基于以下示例图
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)
KNOWS 关系类型被认为是双向的,如果 Michael 认识 Emil,我们可以推断 Emil 也认识 Michael。在使用 KNOWS 关系时,我们将忽略方向。
FOLLOWS 关系是有方向的,因此我们在使用它时会指定方向。
查找指定跳数的邻居
apoc.neighbors.athop 过程计算节点在特定跳数时的邻域。
KNOWS 的人MATCH (p:Person {name: "Emil"})
CALL apoc.neighbors.athop(p, "KNOWS", 1)
YIELD node
RETURN node
| 节点 |
|---|
(:Person {name: "Michael"}) |
Emil 与 Michael 仅有直接的 KNOWS 关系,因此 Michael 是此查询返回的唯一节点。
KNOWS 的人MATCH (p:Person {name: "Emil"})
CALL apoc.neighbors.athop(p, "KNOWS", 2)
YIELD node
RETURN node
| 节点 |
|---|
(:Person {name: "Praveena"}) |
(:Person {name: "Lju"}) |
Michael 也 KNOWS Praveena 和 Lju,由于 Emil 与他们没有直接的 KNOWS 关系,因此他在 2 跳距离内才 KNOWS 他们。如果我们不关心邻域中具体是哪些节点,而只想知道数量,我们也可以这样做。
KNOWS 的人数MATCH (p:Person {name: "Emil"})
CALL apoc.neighbors.athop.count(p, "KNOWS", 2)
YIELD value
RETURN value
| 值 |
|---|
2 |
正如预期的那样,我们得到了 2 的计数,这些人分别是 Praveena 和 Lju!
查找指定跳数范围内的邻居
apoc.neighbors.byhop 过程计算节点在多个跳数时的邻域。
KNOWS 的人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 如何认识这些人:
-
(emil)-[:KNOWS]-(michael)
-
(emil)-[:KNOWS]-(michael)-[:KNOWS]-(lju) -
(emil)-[:KNOWS]-(michael)-[:KNOWS]-(praveena)
我们在搜索邻域时也可以使用多种关系类型。
假设除了查找 Emil 认识的人之外,我们还想查找关注他的人。我们可以通过使用 < 来表示入向关系,或使用 > 来表示出向关系,从而指定关系类型的方向。因此,要查找关注 Emil 的人,我们将使用 <FOLLOWS。
KNOWS 的人以及关注他的人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 如何认识这些人:
-
(emil)-[:KNOWS]-(michael) -
(mark)-[:FOLLOWS]→(emil)
-
(emil)-[:KNOWS]-(michael)-[:KNOWS]-(lju) -
(emil)-[:KNOWS]-(michael)-[:KNOWS]-(praveena) -
(joe)-[:FOLLOWS]→(mark)-[:FOLLOWS]→(emil)
-
(ryan)-[:FOLLOWS]→(joe)-[:FOLLOWS]→(mark)-[:FOLLOWS]→(emil)
并且,与 apoc.neighbors.athop 过程一样,我们也可以只返回每一跳的邻域大小。
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。
我们甚至可以将该数字列表转换为映射,其中键是跳数,值是邻域大小。以下查询展示了如何使用 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
| 值 |
|---|
{ |
查找直到指定跳数的邻居
apoc.neighbors.tohop 过程计算节点直到指定跳数的邻域。
FOLLOWS 的人MATCH (p:Person {name: "Praveena"})
CALL apoc.neighbors.tohop(p, "FOLLOWS>", 1)
YIELD node
RETURN node
| 节点 |
|---|
(:Person {name: "Joe"}) |
Praveena 唯一关注的人是 Joe,所以这是返回的唯一节点。如果我们包含最多 2 跳的人会怎样?
FOLLOWS 的人MATCH (p:Person {name: "Praveena"})
CALL apoc.neighbors.tohop(p, "FOLLOWS>", 2)
YIELD node
RETURN node
| 节点 |
|---|
(:Person {name: "Mark"}) |
(:Person {name: "Joe"}) |
现在 Mark 也被返回了。以下图模式描述了 Praveena 关注的人:
-
(praveena)-[:FOLLOWS]-(joe) -
(praveena)-[:FOLLOWS]-(joe)-[:FOLLOWS]→(mark)
如果我们只想要人数统计,可以使用计数变体。
FOLLOWS 的人数MATCH (p:Person {name: "Praveena"})
CALL apoc.neighbors.tohop.count(p, "FOLLOWS>", 2)
YIELD value
RETURN value
| 值 |
|---|
2 |