扩展到子图中的节点
此过程根据标签过滤器,沿 RELATIONSHIP(关系)值扩展到从起始 NODE(节点)可到达的最大层级的子图 NODE 值。它允许对扩展子图的遍历进行细粒度控制。
过程概述
该过程描述如下
| 限定名称 | 类型 |
|---|---|
apoc.path.subgraphNodes |
|
配置参数
该过程支持以下配置参数
| 名称 (name) | type | 默认 | description(描述) |
|---|---|---|---|
minLevel |
INTEGER(整数) |
-1 |
遍历的最小跳数。如果指定,必须为 0 或 1 |
maxLevel |
INTEGER(整数) |
-1 |
遍历的最大跳数 |
relationshipFilter |
STRING |
null |
要遍历的关系类型和方向。 请参阅 关系过滤器。 |
labelFilter |
STRING |
null |
要遍历的节点标签。 请参阅 标签过滤器。 |
beginSequenceAtStart |
布尔值 (BOOLEAN) |
true |
从距离起始节点一步之遥的位置开始匹配节点标签和/或关系类型序列(在 |
bfs |
布尔值 (BOOLEAN) |
true |
遍历时使用广度优先搜索。如果设置为 |
filterStartNode |
布尔值 (BOOLEAN) |
false |
|
limit |
INTEGER(整数) |
-1 |
限制返回的路径数量。当使用 |
endNodes |
LIST<NODE> |
null |
只有这些节点可以结束返回的路径,如果可能,扩展将继续经过这些节点。 |
terminatorNodes |
LIST<NODE> |
null |
只有这些节点可以结束返回的路径,并且扩展不会在这些节点之后继续。 |
allowlistNodes |
LIST<NODE> |
null |
只有这些节点允许在扩展中出现(如果存在,endNodes 和 terminatorNodes 也将被允许)。 |
denylistNodes |
LIST<NODE> |
null |
返回的所有路径都不会包含这些节点。 |
whitelistNodes (已弃用) |
LIST<NODE> |
null |
请参阅 allowlistNodes。 |
blacklistNodes (已弃用) |
LIST<NODE> |
null |
请参阅 denylistNodes。 |
它还有以下固定参数
| 名称 (name) | type | 默认 | description(描述) |
|---|---|---|---|
uniqueness |
STRING |
NODE_GLOBAL |
在遍历中展开关系时使用的策略。 |
关系过滤器
关系过滤器是由逗号分隔的过滤器序列。单个过滤器是一个或多个由 | 分隔的模式。
最简单的关系过滤器只有一个过滤器,应用于遍历的每一个关系。我们稍后将讨论更长序列的行为。
单个关系过滤器的语法描述如下
语法: [<]RELATIONSHIP_TYPE1[>]|[<]RELATIONSHIP_TYPE2[>]|…
| input | type | 方向 |
|---|---|---|
|
|
OUTGOING (出站) |
|
|
INCOMING (入站) |
|
|
BOTH (双向) |
|
|
OUTGOING (出站) |
|
|
INCOMING (入站) |
标签过滤器
标签过滤器是由逗号分隔的过滤器序列。单个过滤器是一个或多个由 | 分隔的模式。
最简单的标签过滤器只有一个过滤器,应用于访问的每一个节点。我们稍后将讨论更长序列的行为。
单个标签过滤器的语法描述如下
语法: [+-/>]LABEL1|LABEL2|*|…
| 符号 | 过滤器类型 | 输入示例 | 描述 |
|---|---|---|---|
|
黑名单 (Denylist) |
|
路径中的任何节点都不会拥有存在于黑名单中的标签。 |
|
白名单 (Allowlist) |
|
路径中的所有节点必须拥有白名单中的标签(如果使用这些过滤器,则豁免终止和结束节点)。如果没有白名单运算符,则允许所有标签。 |
|
终止 (Termination) |
|
只返回到达具有给定标签节点的路径,并在该点停止进一步扩展。终止节点不需要遵守白名单。终止过滤优先于结束节点过滤。 |
|
结束节点 (End node) |
|
只返回到达具有给定标签节点的路径,但继续扩展以匹配其后的结束节点。结束节点不需要遵守白名单即可被返回,但只有在节点具有白名单中的标签时,才允许在其后进行扩展。 |
|
复合标签 |
|
这返回标签的合取,例如 /Foo:Bar 意味着终止节点必须同时匹配 |
标签过滤运算符的优先级和行为
允许多个标签过滤器同时使用。请看以下示例
labelFilter:'+Person|Movie|-SciFi|>Western|/Romance'
如果我们分析这个标签过滤器,可以看到
-
:Person和:Movie标签在白名单中 -
:SciFi在黑名单中 -
:Western是结束节点标签 -
:Romance是终止标签。
运算符评估的优先级不依赖于它们在 labelFilter 中的位置,而是固定的
黑名单过滤器 -,终止过滤器 /,结束节点过滤器 >,白名单过滤器 +。
这意味着
-
没有列入黑名单的标签
-会出现在返回路径的节点中,即使相同的标签(或具有黑名单标签节点的其他标签)包含在其他过滤器列表中。 -
如果使用了终止过滤器
/或结束节点过滤器>,则仅返回到达具有这些标签的节点的路径。这些结束节点豁免于白名单过滤器。 -
如果一个节点是终止节点
/,则不会在该节点之后进行进一步扩展。 -
白名单仅适用于除终止节点或结束节点过滤器定义的节点之外的路径节点。如果没有结束节点或终止节点运算符,则白名单适用于路径的所有节点。
-
如果 labelFilter 中不存在白名单运算符,则视为所有标签均在白名单中。
示例
本节中的示例基于以下示例图
MERGE (mark:Person:DevRel {name: "Mark"})
MERGE (lju:Person:DevRel {name: "Lju"})
MERGE (praveena:Person:Engineering {name: "Praveena"})
MERGE (zhen:Person:Engineering {name: "Zhen"})
MERGE (martin:Person:Engineering {name: "Martin"})
MERGE (joe:Person:Field {name: "Joe"})
MERGE (stefan:Person:Field {name: "Stefan"})
MERGE (alicia:Person:Product {name: "Alicia"})
MERGE (jake:Person:Product {name: "Jake"})
MERGE (john:Person:Product {name: "John"})
MERGE (jonny:Person:Sales {name: "Jonny"})
MERGE (anthony:Person:Sales {name: "Anthony"})
MERGE (rik:Person:Sales {name: "Rik"})
MERGE (zhen)-[:KNOWS]-(stefan)
MERGE (zhen)-[:KNOWS]-(lju)
MERGE (zhen)-[:KNOWS]-(praveena)
MERGE (zhen)-[:KNOWS]-(martin)
MERGE (mark)-[:KNOWS]-(jake)
MERGE (alicia)-[:KNOWS]-(jake)
MERGE (jonny)-[:KNOWS]-(anthony)
MERGE (john)-[:KNOWS]-(rik)
MERGE (alicia)-[:FOLLOWS]->(joe)
MERGE (joe)-[:FOLLOWS]->(mark)
MERGE (joe)-[:FOLLOWS]->(praveena)
MERGE (joe)-[:FOLLOWS]->(zhen)
MERGE (mark)-[:FOLLOWS]->(stefan)
MERGE (stefan)-[:FOLLOWS]->(joe)
MERGE (praveena)-[:FOLLOWS]->(joe)
MERGE (lju)-[:FOLLOWS]->(jake)
MERGE (alicia)-[:FOLLOWS]->(jonny)
MERGE (zhen)-[:FOLLOWS]->(john)
MERGE (anthony)-[:FOLLOWS]->(joe)
下面的 Neo4j 浏览器可视化显示了示例图
KNOWS 关系类型被认为是双向的,如果 Zhen 认识 Stefan,我们可以暗示 Stefan 也认识 Zhen。当使用 KNOWS 关系时,我们将忽略方向。
FOLLOWS 关系是有方向的,因此我们在使用它时会指定方向。
关系类型和节点标签过滤器
让我们从 Praveena 节点开始展开路径。我们只想考虑 KNOWS 关系类型,因此我们将把它指定为 relationshipFilter 参数。
KNOWS 关系在 1 到 2 跳范围内可到达的人员MATCH (p:Person {name: "Praveena"})
CALL apoc.path.subgraphNodes(p, {
relationshipFilter: "KNOWS",
minLevel: 1,
maxLevel: 2
})
YIELD node
RETURN node;
| 节点 |
|---|
(:Person:Engineering {name: "Zhen"}) |
(:Person:Engineering {name: "Martin"}) |
(:Person:DevRel {name: "Lju"}) |
(:Person:Field {name: "Stefan"}) |
从 Praveena 可到达 4 个人。
我们还可以提供节点标签过滤器来限制返回的节点。如果我们只想返回每个节点都带有 Engineering 标签的路径,我们将给 labelFilter 参数提供值 +Engineering。
KNOWS 关系在 1 到 2 跳范围内可到达的 Engineering 人员MATCH (p:Person {name: "Praveena"})
CALL apoc.path.subgraphNodes(p, {
relationshipFilter: "KNOWS",
labelFilter: "+Engineering",
minLevel: 1,
maxLevel: 2
})
YIELD node
RETURN node;
| 节点 |
|---|
(:Person:Engineering {name: "Zhen"}) |
(:Person:Engineering {name: "Martin"}) |
我们丢失了 Lju 和 Stefan,因为这些节点没有 Engineering 标签。
我们可以指定多种关系类型。以下查询从 Alicia 节点开始,然后展开 FOLLOWS 和 KNOWS 关系
FOLLOWS 或 KNOWS 关系在 1 到 3 跳范围内可到达的人员MATCH (p:Person {name: "Alicia"})
CALL apoc.path.subgraphNodes(p, {
relationshipFilter: "FOLLOWS>|KNOWS",
minLevel: 1,
maxLevel: 3
})
YIELD node
RETURN node;
| 节点 |
|---|
(:Person:Sales {name: "Jonny"}) |
(:Person:Field {name: "Joe"}) |
(:Person:Product {name: "Jake"}) |
(:Person:Sales {name: "Anthony"}) |
(:Person:Engineering {name: "Praveena"}) |
(:Person:DevRel {name: "Mark"}) |
(:Person:Engineering {name: "Zhen"}) |
(:Person:Field {name: "Stefan"}) |
(:Person:Product {name: "John"}) |
(:Person:Engineering {name: "Martin"}) |
(:Person:DevRel {name: "Lju"}) |
此列表包含了图中除一人之外的所有人员,这意味着 Alicia 的社交关系非常广泛。
我们还可以使用标签过滤器指定遍历终止标准。如果我们想在遍历遇到包含 Engineering 标签的节点时立即终止遍历,我们可以使用 /Engineering 节点过滤器。
FOLLOWS 或 KNOWS 关系在 1 到 3 跳范围内可到达的人员,一旦到达带有 Engineering 标签的节点即终止MATCH (p:Person {name: "Alicia"})
CALL apoc.path.subgraphNodes(p, {
relationshipFilter: "FOLLOWS>|KNOWS",
labelFilter: "/Engineering",
minLevel: 1,
maxLevel: 3
})
YIELD node
RETURN node;
| 节点 |
|---|
(:Person:Engineering {name: "Zhen"}) |
(:Person:Engineering {name: "Praveena"}) |
现在我们只剩下 2 个人 - Zhen 和 Praveena。但此查询没有捕获所有以带有 Engineering 标签的节点结尾的 Alicia 路径。我们可以使用 >Engineering 节点过滤器来定义一个遍历,该遍历
-
仅返回带有
Engineering标签的节点 -
在此之后继续向终点节点扩展,寻找更多带有
Engineering标签的节点
FOLLOWS 或 KNOWS 关系在 1 到 3 跳范围内可到达的 Engineering 人员MATCH (p:Person {name: "Alicia"})
CALL apoc.path.subgraphNodes(p, {
relationshipFilter: "FOLLOWS>|KNOWS",
labelFilter: ">Engineering",
minLevel: 1,
maxLevel: 3
})
YIELD node
RETURN node;
| 节点 |
|---|
(:Person:Engineering {name: "Zhen"}) |
(:Person:Engineering {name: "Praveena"}) |
(:Person:Engineering {name: "Martin"}) |
我们的查询现在也返回了 Martin,他一定是通过 Zhen 或 Praveena 可达的。
终止节点和终点节点
除了为遍历指定终止标签和终点标签外,我们还可以指定终止节点和终点节点。对于此过程,这两个参数的行为相同——该过程将确定作为终止节点或终点节点提供的任何节点是否可以从起始节点到达。
让我们基于之前的查询进行扩展,该查询找出了 Alicia KNOWS 或 FOLLOWS 的人。我们想知道是否有一种方法可以从 Alicia 到达 Joe,我们可以通过将 Joe 节点传递给 terminatorNodes 参数来实现。
FOLLOWS 或 KNOWS 关系在 1 到 3 跳范围内可到达的终止节点MATCH (p:Person {name: "Alicia"})
MATCH (joe:Person {name: "Joe"})
CALL apoc.path.subgraphNodes(p, {
relationshipFilter: "FOLLOWS>|KNOWS",
minLevel: 1,
maxLevel: 3,
terminatorNodes: [joe]
})
YIELD node
RETURN node;
| 节点 |
|---|
(:Person:Field {name: "Joe"}) |
我们确实有一条从 Alicia 到 Joe 的路径。
我们从之前的示例中知道,Alicia 实际上可以使用 KNOWS 或 FOLLOWS 关系到达图中的所有其他节点。但是,如果我们想确定仅使用 KNOWS 关系是否可以到达 Mark、Joe、Zhen 和 Praveena,该怎么办?
KNOWS 关系在 1 到 3 跳范围内可到达的终点节点MATCH (p:Person {name: "Alicia"})
MATCH (end:Person)
WHERE end.name IN ["Mark", "Joe", "Zhen", "Praveena"]
WITH p, collect(end) AS endNodes
CALL apoc.path.subgraphNodes(p, {
relationshipFilter: "KNOWS",
minLevel: 1,
maxLevel: 3,
endNodes: endNodes
})
YIELD node
RETURN node;
| 节点 |
|---|
(:Person:DevRel {name: "Mark"}) |
只有 Mark 可到达!
允许列表节点和拒绝列表节点
还可以指定白名单和黑名单节点。
让我们基于找到 Alicia KNOWS 或 FOLLOWS 的人的查询进行扩展。我们想找到仅包含 Jonny、Mark 或 Zhen 的路径所能到达的节点。我们可以通过将这些节点传递给 allowlistNodes 参数来做到这一点。
FOLLOWS 或 KNOWS 关系类型到达的节点,其中到达这些节点的路径必须仅包含 Mark、Jonny 或 ZhenMATCH (p:Person {name: "Alicia"})
MATCH (allowlist:Person)
WHERE allowlist.name IN ["Jonny", "Mark", "Zhen"]
WITH p, collect(allowlist) AS allowlistNodes
CALL apoc.path.subgraphNodes(p, {
relationshipFilter: "FOLLOWS>|KNOWS",
minLevel: 1,
maxLevel: 3,
allowlistNodes: allowlistNodes
})
YIELD node
RETURN node;
| 节点 |
|---|
(:Person:Sales {name: "Jonny"}) |
只有 Jonny 可以到达。因此我们可以推断 Mark 和 Zhen 只能通过未包含在白名单中的其他节点到达。
黑名单用于从通往可到达节点的路径中排除节点。如果我们想返回在不经过 Joe 的情况下可以到达的节点,我们可以通过将 Joe 节点传递给 denylistNodes 参数来实现。
FOLLOWS 或 KNOWS 关系类型到达的节点,其中到达这些节点的路径不经过 JoeMATCH (p:Person {name: "Alicia"})
MATCH (joe:Person {name: "Joe"})
CALL apoc.path.subgraphNodes(p, {
relationshipFilter: "FOLLOWS>|KNOWS",
minLevel: 1,
maxLevel: 3,
denylistNodes: [joe]
})
YIELD node
RETURN node;
| 节点 |
|---|
(:Person:Sales {name: "Jonny"}) |
(:Person:Product {name: "Jake"}) |
(:Person:Sales {name: "Anthony"}) |
(:Person:DevRel {name: "Mark"}) |
(:Person:Field {name: "Stefan"}) |
在不经过 Joe 节点的情况下,只有 5 个节点是可到达的。如果我们回顾之前的示例,当我们没有指定拒绝列表时,有 11 个节点是可到达的。这表明 Joe 是该图中的一个重要连接点。
关系类型序列
可以通过逗号分隔传递给 relationshipFilter 的值来指定关系类型的序列。
例如,如果我们想从 Joe 节点开始,遍历 FOLLOWS 关系(出站方向)和 KNOWS 关系(任一方向)的序列,我们可以指定关系过滤器 FOLLOWS>,KNOWS。
FOLLOWS 和 KNOWS 关系类型所能到达的节点MATCH (p:Person {name: "Joe"})
CALL apoc.path.subgraphNodes(p, {
relationshipFilter: "FOLLOWS>,KNOWS",
beginSequenceAtStart: true,
minLevel: 1,
maxLevel: 4
})
YIELD node
RETURN node;
| 节点 |
|---|
(:Person:Engineering {name: "Praveena"}) |
(:Person:DevRel {name: "Mark"}) |
(:Person:Engineering {name: "Zhen"}) |
(:Person:Product {name: "Jake"}) |
(:Person:Engineering {name: "Martin"}) |
(:Person:DevRel {name: "Lju"}) |
(:Person:Field {name: "Stefan"}) |