扩展到子图中的节点

此过程将从起始NODE扩展到子图中的NODE值,遵循关系值直到最大级别,并遵循标签过滤器。它允许对扩展子图的遍历进行精细控制。

过程概述

该过程描述如下

限定名称 类型

apoc.path.subgraphNodes
apoc.path.subgraphNodes(startNode ANY, config MAP<STRING, ANY>) - 返回从起始NODE通过给定RELATIONSHIP类型到最大深度可达的子图中的NODE值。

过程

配置参数

该过程支持以下配置参数

表1. 配置参数
名称 类型 默认值 描述

minLevel

INTEGER

-1

遍历中的最小跳数。如果指定,必须为 0 或 1

maxLevel

INTEGER

-1

遍历中的最大跳数

relationshipFilter

STRING

null

要遍历的关系类型和方向。

参阅关系过滤器

labelFilter

STRING

null

要遍历的节点标签。

参阅标签过滤器

beginSequenceAtStart

BOOLEAN

true

从起始节点向外一个节点开始匹配节点标签和/或关系类型序列(在relationshipFilterlabelFiltersequences中定义)。

bfs

BOOLEAN

true

遍历时使用广度优先搜索。如果设置为false则使用深度优先搜索

filterStartNode

BOOLEAN

false

labelFiltersequence是否适用于扩展的起始节点。

limit

INTEGER

-1

限制返回的路径数量。当使用bfs:true时,这会返回到终止或末端节点过滤器中带有标签的n个最近节点的路径,其中n是给定的限制。如果设置为true,则当扩展通常因无结果而消除行时,将生成null值。

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。

它还有以下固定参数

表2. 配置参数
名称 类型 默认值 描述

uniqueness

STRING

NODE_GLOBAL

遍历中扩展关系的策略。NODE_GLOBAL表示节点不能被遍历多次。这是传统遍历框架的做法。

关系过滤器

关系过滤器是由逗号分隔的过滤器序列。单个过滤器是由 | 分隔的一个或多个模式。

最简单的关系过滤器只有一个过滤器,它应用于遍历的每个关系。我们稍后将讨论较长序列的行为。

单个关系过滤器的语法描述如下

语法:[<]RELATIONSHIP_TYPE1[>]|[<]RELATIONSHIP_TYPE2[>]|…​

输入 类型 方向

LIKES>

LIKES

出站

<FOLLOWS

FOLLOWS

入站

KNOWS

KNOWS

双向

>

任意类型

出站

<

任意类型

入站

标签过滤器

标签过滤器是由逗号分隔的过滤器序列。单个过滤器是由 | 分隔的一个或多个模式。

最简单的标签过滤器只有一个过滤器,它应用于访问的每个节点。我们稍后将讨论较长序列的行为。

单个标签过滤器的语法描述如下

语法:[+-/>]LABEL1|LABEL2|*|…​

符号 过滤类型 输入示例 描述

-

拒绝列表

-Foe

路径中的任何节点都不会包含拒绝列表中存在的标签。

+

允许列表

+Friend

路径中的所有节点必须包含允许列表中的标签(终止和末端节点除外,如果使用这些过滤器)。如果不存在允许列表操作符,则允许所有标签。

/

终止

/Friend

只返回到具有给定标签的节点为止的路径,并停止在该节点之外的进一步扩展。终止节点不必遵守允许列表。终止过滤优先于末端节点过滤。

>

末端节点

>Friend

只返回到具有给定标签的节点为止的路径,但继续扩展以匹配其后的末端节点。末端节点不必遵守允许列表才能返回,但只有当节点具有允许列表中的标签时才允许在其后继续扩展。

:

复合标签

Foe:Friend

这会返回标签的合取,例如 /Foo:Bar 表示终止节点必须同时匹配FooBar。要包含不具有特殊含义的:在标签中,请使用\对其进行转义,例如 Foo\:Bar 是标签Foo:Bar

标签过滤器运算符的优先级和行为

允许同时使用多个标签过滤器运算符。以下示例:

labelFilter:'+Person|Movie|-SciFi|>Western|/Romance'

通过此标签过滤器,我们可以看到:

  • :Person:Movie标签在允许列表中

  • :SciFi在拒绝列表中

  • :Western是末端节点标签

  • :Romance是终止标签。

运算符评估的优先级不取决于它们在 labelFilter 中的位置,而是固定的:

拒绝列表过滤器-、终止过滤器/、末端节点过滤器>、允许列表过滤器+

这意味着

  • 拒绝列表中的标签-绝不会出现在返回路径的节点中,即使同一标签(或具有拒绝列表标签的节点的另一个标签)包含在另一个过滤列表中。

  • 如果使用终止过滤器/或末端节点过滤器>,则只返回到具有这些标签的节点为止的路径作为结果。这些末端节点不受允许列表过滤器的限制。

  • 如果节点是终止节点/,则不会在该节点之外进行进一步的扩展。

  • 允许列表仅适用于直到但不包括终止或末端节点过滤器中的末端节点。如果 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 Browser 可视化显示了示例图:

apoc.path.expandConfig
图1. 示例图

KNOWS关系类型被认为是双向的,如果 Zhen 认识 Stefan,我们可以推断 Stefan 认识 Zhen。当使用KNOWS关系时,我们将忽略方向。

FOLLOWS关系有方向,因此在使用时我们会指定方向。

关系类型和节点标签过滤器

让我们从 Praveena 节点开始扩展路径。我们只考虑KNOWS关系类型,因此我们将其指定为relationshipFilter参数。

以下返回 Praveena 1 到 2 跳范围内通过KNOWS关系可达的人员:
MATCH (p:Person {name: "Praveena"})
CALL apoc.path.subgraphNodes(p, {
	relationshipFilter: "KNOWS",
    minLevel: 1,
    maxLevel: 2
})
YIELD node
RETURN node;
表3. 结果
节点

(:Person:Engineering {name: "Zhen"})

(:Person:Engineering {name: "Martin"})

(:Person:DevRel {name: "Lju"})

(:Person:Field {name: "Stefan"})

从 Praveena 可到达 4 个人。

我们还可以提供节点标签过滤器来限制返回的节点。如果只想返回路径中每个节点都具有Engineering标签的路径,我们将为labelFilter参数提供值+Engineering

以下返回通过KNOWS关系从 Praveena 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;
表4. 结果
节点

(:Person:Engineering {name: "Zhen"})

(:Person:Engineering {name: "Martin"})

我们失去了 Lju 和 Stefan,因为这些节点没有Engineering标签。

我们可以指定多个关系类型。以下查询从 Alicia 节点开始,然后扩展FOLLOWSKNOWS关系:

以下返回从 Alicia 1 到 3 跳范围内通过FOLLOWSKNOWS关系可达的人员:
MATCH (p:Person {name: "Alicia"})
CALL apoc.path.subgraphNodes(p, {
    relationshipFilter: "FOLLOWS>|KNOWS",
    minLevel: 1,
    maxLevel: 3
})
YIELD node
RETURN node;
表5. 结果
节点

(: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节点过滤器。

以下返回从 Alicia 1 到 3 跳范围内通过FOLLOWSKNOWS关系可达的人员,一旦到达具有Engineering标签的节点就终止:
MATCH (p:Person {name: "Alicia"})
CALL apoc.path.subgraphNodes(p, {
    relationshipFilter: "FOLLOWS>|KNOWS",
    labelFilter: "/Engineering",
    minLevel: 1,
    maxLevel: 3
})
YIELD node
RETURN node;
表6. 结果
节点

(:Person:Engineering {name: "Zhen"})

(:Person:Engineering {name: "Praveena"})

我们现在只剩下 2 个人——Zhen 和 Praveena。但是这个查询没有捕获从 Alicia 出发、终止于具有Engineering标签的所有路径。我们可以使用>Engineering节点过滤器来定义一个遍历,该遍历:

  • 只返回带有Engineering标签的节点

  • 在此之后继续扩展到末端节点,寻找更多带有Engineering标签的节点

以下返回从 Alicia 1 到 3 跳范围内通过FOLLOWSKNOWS关系可达的Engineering人员:
MATCH (p:Person {name: "Alicia"})
CALL apoc.path.subgraphNodes(p, {
    relationshipFilter: "FOLLOWS>|KNOWS",
    labelFilter: ">Engineering",
    minLevel: 1,
    maxLevel: 3
})
YIELD node
RETURN node;
表7. 结果
节点

(:Person:Engineering {name: "Zhen"})

(:Person:Engineering {name: "Praveena"})

(:Person:Engineering {name: "Martin"})

我们的查询现在也返回了 Martin,他一定是通过 Zhen 或 Praveena 才能到达。

终止节点和末端节点

除了指定遍历的终止和末端标签外,我们还可以指定终止和末端节点。对于此过程,这些参数的行为方式相同——该过程将确定作为终止或末端节点提供的任何节点是否可以从起始节点到达。

让我们在之前的查询基础上进行构建,该查询查找 Alicia KNOWSFOLLOWS的人员。我们想知道是否有办法从 Alicia 到 Joe,我们可以通过将 Joe 节点传递给terminatorNodes参数来实现。

以下返回从 Alicia 1 到 3 跳范围内通过FOLLOWSKNOWS关系可达的终止节点:
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;
表8. 结果
节点

(:Person:Field {name: "Joe"})

我们确实有一条从 Alicia 到 Joe 的路径。

我们从前面的一个例子中得知,Alicia 实际上可以使用KNOWSFOLLOWS关系到达图中的所有其他节点。但是,如果我们只想确定 Mark、Joe、Zhen 和 Praveena 是否仅使用KNOWS关系即可到达呢?

以下返回从 Alicia 1 到 3 跳范围内通过KNOWS关系可达的末端节点:
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;
表9. 结果
节点

(:Person:DevRel {name: "Mark"})

只有 Mark 可以到达!

允许列表节点和拒绝列表节点

还可以指定允许列表和拒绝列表节点。

让我们基于找到 Alicia KNOWSFOLLOWS的人的查询。我们想找到只能通过 Jonny、Mark 或 Zhen 包含的路径可到达的节点。我们可以通过将这些节点传递给参数allowlistNodes来实现。

以下返回从 Alicia 1 到 3 跳范围内通过FOLLOWSKNOWS关系类型可到达的节点,其中到达这些节点的路径必须只包含 Mark、Jonny 或 Zhen:
MATCH (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;
表10. 结果
节点

(:Person:Sales {name: "Jonny"})

只有 Jonny 可以被接触到。因此我们可以推断 Mark 和 Zhen 只能通过未包含在允许列表中的另一个节点来接触到。

拒绝列表用于从通向可达节点的路径中排除节点。如果我们想返回不经过 Joe 的可达节点,我们可以通过将 Joe 节点传递给denylistNodes参数来实现。

以下返回从 Alicia 1 到 3 跳范围内通过FOLLOWSKNOWS关系类型可达的节点,其中到达这些节点的路径不经过 Joe:
MATCH (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;
表11. 结果
节点

(:Person:Sales {name: "Jonny"})

(:Person:Product {name: "Jake"})

(:Person:Sales {name: "Anthony"})

(:Person:DevRel {name: "Mark"})

(:Person:Field {name: "Stefan"})

只有 5 个节点可以不经过 Joe 节点到达。如果我们回想一个早期的例子,当我们没有指定拒绝列表时,有 11 个节点可以到达。这表明 Joe 在这个图中是一个重要的连接器。

关系类型序列

关系类型序列可以通过逗号分隔传递给relationshipFilter的值来指定。

例如,如果我们想从 Joe 节点开始,并遍历出站方向的FOLLOWS关系和任一方向的KNOWS关系的序列,我们可以指定关系过滤器FOLLOWS>,KNOWS

以下返回通过从 Joe 交替遵循FOLLOWSKNOWS关系类型可达的节点:
MATCH (p:Person {name: "Joe"})
CALL apoc.path.subgraphNodes(p, {
	relationshipFilter: "FOLLOWS>,KNOWS",
	beginSequenceAtStart: true,
	minLevel: 1,
	maxLevel: 4
})
YIELD node
RETURN node;
表12. 结果
节点

(: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"})

© . All rights reserved.