|| apoc.path.spanningTree - APOC 核心文档 - Neo4j 文档

apoc.path.spanningTree

此过程不被认为可在多线程环境下安全运行。因此,并行运行时不支持此过程。欲了解更多信息,请参阅Cypher 手册 → 并行运行时

详情

语法

apoc.path.spanningTree(startNode, config) :: (path)

描述

返回从起始NODE展开、沿给定RELATIONSHIP类型到最大深度的生成树PATH值。

输入参数

名称

类型

描述

startNode

ANY

启动算法的节点。startNode可以是STRING (elementId())、INTEGER (id())、NODELIST<STRING | INTEGER | NODE>类型。

config

{ minLevel = -1 :: INTEGER, maxLevel = -1 :: INTEGER, relationshipFilter :: STRING, labelFilter :: STRING, beginSequenceAtStart = true :: BOOLEAN, uniqueness = "RELATIONSHIP_PATH" :: STRING, bfs = true :: BOOLEAN, filterStartNode = false :: BOOLEAN, limit = -1 :: INTEGER, optional = false :: BOOLEAN, endNodes :: LIST<NODES>, terminatorNodes:: LIST<NODES>, allowlistNodes:: LIST<NODES>, denylistNodes:: LIST<NODES> }

返回参数

path

名称

类型

描述

PATH

生成树路径。

配置参数

该过程支持以下配置参数

配置参数

默认值
名称 类型 minLevel 描述

INTEGER

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

-1

maxLevel

遍历中的最大跳数

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

-1

relationshipFilter

STRING

null

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

请参阅关系过滤器

labelFilter

要遍历的节点标签。

null

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

请参阅标签过滤器

beginSequenceAtStart

BOOLEAN

true

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

bfs

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

true

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

filterStartNode

false

true

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

limit

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

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

-1

endNodes

LIST<NODE>

只有这些节点可以作为返回路径的终点,并且如果可能,扩展将继续越过这些节点。

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

terminatorNodes

只有这些节点可以作为返回路径的终点,并且扩展不会越过这些节点。

只有这些节点可以作为返回路径的终点,并且如果可能,扩展将继续越过这些节点。

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

allowlistNodes

扩展中只允许这些节点(如果存在,endNodes 和 terminatorNodes 也将被允许)。

只有这些节点可以作为返回路径的终点,并且如果可能,扩展将继续越过这些节点。

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

denylistNodes

返回的路径都不会包含这些节点。

只有这些节点可以作为返回路径的终点,并且如果可能,扩展将继续越过这些节点。

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

whitelistNodes (已弃用)

请参阅 allowlistNodes。

只有这些节点可以作为返回路径的终点,并且如果可能,扩展将继续越过这些节点。

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

blacklistNodes (已弃用)

请参阅 denylistNodes。

只有这些节点可以作为返回路径的终点,并且如果可能,扩展将继续越过这些节点。

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

它还有以下固定参数

uniqueness

默认值
名称 类型 minLevel 描述

NODE_GLOBAL

null

遍历中扩展关系时使用的策略。NODE_GLOBAL表示一个节点不能被遍历多次。这是旧版遍历框架的做法。

关系过滤器

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

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

输入

类型 方向 LIKES>

LIKES

出站

<FOLLOWS

FOLLOWS

入站

KNOWS

双向

双向

任意类型

>

标签过滤器

<FOLLOWS

<

标签过滤器

KNOWS

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

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

符号

过滤类型 输入示例 拒绝列表 描述

-

-Foe

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

允许列表

+

+Friend

路径中的所有节点都必须具有允许列表中的标签(如果使用终止和结束节点过滤器,则排除这些节点)。如果没有允许列表运算符,则允许所有标签。

终止

/

/Friend

只返回到达具有给定标签的节点的路径,并停止进一步的扩展。终止节点不必遵守允许列表。终止过滤优先于结束节点过滤。

结束节点

>

>Friend

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

复合标签

:

Foe:Friend

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

这会返回标签的合取(即逻辑“与”),例如 /Foo:Bar 意味着终止节点必须同时匹配 FooBar。要在标签中包含没有特殊含义的 :,请使用 \ 进行转义,例如 Foo\:Bar 就是标签 Foo:Bar

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

允许多个标签过滤器运算符同时使用。以下面的例子为例

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

如果我们分析这个标签过滤器,可以看到

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

  • :SciFi在拒绝列表中

  • :Western是一个结束节点标签

  • :Romance是一个终止标签。

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

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

这意味着

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

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

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

  • 允许列表仅适用于到达但不包括终止或结束节点过滤器中的结束节点的节点。如果没有结束节点或终止节点运算符,则允许列表适用于路径中的所有节点。

  • 如果 labelFilter 中不存在允许列表运算符,则视为所有标签都已列入允许列表。

输出参数

名称 类型

PATH

生成树路径。

使用示例

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

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 开始、遍历KNOWS关系类型 1 到 2 跳的生成树
MATCH (p:Person {name: "Praveena"})
CALL apoc.path.spanningTree(p, {
	relationshipFilter: "KNOWS",
    minLevel: 1,
    maxLevel: 2
})
YIELD path
RETURN path;

我们可以在来自 Praveena 的生成树中看到该生成树的 Neo4j Browser 可视化。

apoc.path.subtree.praveena
图 2. 来自 Praveena 的生成树

除了 Praveena 之外,生成树还包含 4 个节点。Praveena 只与 Zhen 有直接的KNOWS关系,但 Zhen 与另外 3 个人有KNOWS关系,这意味着他们也被包含在生成树中。

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

以下返回从 Praveena 开始、遍历KNOWS关系类型 1 到 2 跳、仅包含Engineering节点的生成树
MATCH (p:Person {name: "Praveena"})
CALL apoc.path.spanningTree(p, {
	relationshipFilter: "KNOWS",
	labelFilter: "+Engineering",
    minLevel: 1,
    maxLevel: 2
})
YIELD path
RETURN path;

我们可以在从 Praveena 到 Engineering 节点的生成树中看到该生成树的 Neo4j Browser 可视化。

apoc.path.subtree.praveena eng
图 3. 从 Praveena 到 Engineering 节点的生成树

我们从生成树中失去了 Lju 和 Stefan,因为这两个节点都没有Engineering标签。

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

以下返回从 Alicia 开始、遍历FOLLOWSKNOWS关系类型 1 到 3 跳的生成树
MATCH (p:Person {name: "Alicia"})
CALL apoc.path.spanningTree(p, {
    relationshipFilter: "FOLLOWS>|KNOWS",
    minLevel: 1,
    maxLevel: 3
})
YIELD path
RETURN path;

我们可以在来自 Alicia 的生成树中看到该生成树的 Neo4j Browser 可视化。

apoc.path.subtree.alicia
图 4. 来自 Alicia 的生成树

此查询返回图中 12 个人中 11 个人的路径,这表明 Alicia 连接性非常好。

我们还可以使用标签过滤器指定遍历终止条件。如果希望在遍历遇到包含Engineering标签的节点时立即终止遍历,我们可以使用/Engineering节点过滤器。

以下返回从 Alicia 开始、遍历FOLLOWSKNOWS关系类型 1 到 3 跳的生成树,一旦到达带有Engineering标签的节点即终止
MATCH (p:Person {name: "Alicia"})
CALL apoc.path.spanningTree(p, {
    relationshipFilter: "FOLLOWS>|KNOWS",
    labelFilter: "/Engineering",
    minLevel: 1,
    maxLevel: 3
})
YIELD path
RETURN path;

我们可以在从 Alicia 开始,在Engineering节点终止的生成树中看到该生成树的 Neo4j Browser 可视化。

apoc.path.subtree.alicia eng
图 5. 从 Alicia 开始,在Engineering节点终止的生成树

我们的生成树已缩减到除了 Alicia 之外只有 3 个其他节点。但此查询并未捕获从 Alicia 开始的完整生成树(包含带有Engineering标签的节点)。我们可以使用>Engineering节点过滤器来定义一个遍历,它将

  • 只返回在带有Engineering标签的节点处终止的路径

  • 在此之后继续扩展到结束节点,寻找更多以Engineering标签结尾的路径

以下返回从 Alicia 开始、遍历FOLLOWSKNOWS关系类型 1 到 3 跳的生成树,其中路径以带有Engineering标签的节点结束
MATCH (p:Person {name: "Alicia"})
CALL apoc.path.spanningTree(p, {
    relationshipFilter: "FOLLOWS>|KNOWS",
    labelFilter: ">Engineering",
    minLevel: 1,
    maxLevel: 3
})
YIELD path
RETURN path;

我们可以在从 Alicia 到Engineering节点的生成树中看到该生成树的 Neo4j Browser 可视化。

apoc.path.subtree.alicia eng end
图 6. 从 Alicia 到Engineering节点的生成树

生成树现在也通过 Zhen 的关系到达了 Martin。

终止节点和结束节点

除了为遍历指定终止标签和结束标签外,我们还可以指定终止节点和结束节点。

让我们基于之前找到 Alicia KNOWSFOLLOWS的人的查询进行扩展。我们希望返回的生成树在到达 Mark、Joe、Zhen 或 Praveena 节点时立即停止。我们可以通过将这些节点传递给terminatorNodes参数来实现。

以下返回从 Alicia 开始、遍历FOLLOWSKNOWS关系类型 1 到 3 跳的生成树,一旦到达 Mark、Joe、Zhen 或 Rik 节点即终止
MATCH (p:Person {name: "Alicia"})
MATCH (terminator:Person)
WHERE terminator.name IN ["Mark", "Joe", "Zhen", "Rik"]
WITH p, collect(terminator) AS terminatorNodes
CALL apoc.path.spanningTree(p, {
    relationshipFilter: "FOLLOWS>|KNOWS",
    minLevel: 1,
    maxLevel: 3,
    terminatorNodes: terminatorNodes
})
YIELD path
RETURN path;

我们可以在从 Alicia 开始,在 Mark、Joe、Zhen 或 Rik 处终止的生成树中看到该生成树的 Neo4j Browser 可视化。

apoc.path.subtree.alicia terminator
图 7. 从 Alicia 开始,在 Mark、Joe、Zhen 或 Rik 处终止的生成树

Mark 和 Joe 被包含在生成树中,但 Rik 和 Zhen 无法到达。这可能是因为没有不经过 Mark 和 Joe 的路径可以到达 Zhen 和 Rik,或者这意味着根据其他遍历条件没有路径。

我们可以通过将这些节点传递给endNodes参数来查明 Mark、Joe、Zhen 或 Rik 是否可达。

以下返回从 Alicia 开始、遍历FOLLOWSKNOWS关系类型 1 到 3 跳的生成树,一旦到达 Mark、Joe、Zhen 或 Rik 节点即结束
MATCH (p:Person {name: "Alicia"})
MATCH (end:Person)
WHERE end.name IN ["Mark", "Joe", "Zhen", "Rik"]
WITH p, collect(end) AS endNodes
CALL apoc.path.spanningTree(p, {
    relationshipFilter: "FOLLOWS>|KNOWS",
    minLevel: 1,
    maxLevel: 3,
    endNodes: endNodes
})
YIELD path
RETURN path;

我们可以在从 Alicia 开始,在 Mark、Joe、Zhen 或 Rik 处结束的生成树中看到返回的生成树的 Neo4j Browser 可视化。

apoc.path.subtree.alicia end
图 8. 从 Alicia 开始,在 Mark、Joe、Zhen 或 Rik 处结束的生成树

我们的生成树现在包含了 Joe、Mark 和 Zhen,但 Rik 仍然无法到达。

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

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

让我们基于之前找到 Alicia KNOWSFOLLOWS的人的查询进行扩展。我们希望任何返回的路径只包含节点 Mark、Joe、Zhen 和 Praveena,这可以通过将这些节点传递给allowlistNodes参数来实现。

以下返回从 Alicia 开始、通过FOLLOWSKNOWS关系类型在 1 到 3 跳内可达的生成树,其中到达这些节点的路径必须只包含 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.spanningTree(p, {
    relationshipFilter: "FOLLOWS>|KNOWS",
    minLevel: 1,
    maxLevel: 3,
    allowlistNodes: allowlistNodes
})
YIELD path
RETURN path;

我们可以在从 Alicia 开始,其中到达节点的路径包含 Mark、Jonny 或 Zhen 的生成树中看到返回的生成树的 Neo4j Browser 可视化。

apoc.path.spanningTree.alicia allowlist
图 9. 从 Alicia 开始,其中到达节点的路径包含 Mark、Jonny 或 Zhen 的生成树

只有 Jonny 可达。因此,我们可以推断 Mark 和 Zhen 只能通过未包含在允许列表中的其他节点到达。

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

以下返回从 Alicia 开始、通过FOLLOWSKNOWS关系类型在 1 到 3 跳内可达的生成树,其中到达这些节点的路径不经过 Joe
MATCH (p:Person {name: "Alicia"})
MATCH (joe:Person {name: "Joe"})
CALL apoc.path.spanningTree(p, {
    relationshipFilter: "FOLLOWS>|KNOWS",
    minLevel: 1,
    maxLevel: 3,
    denylistNodes: [joe]
})
YIELD path
RETURN path;

我们可以在从 Alicia 开始,其中到达节点的路径不能经过 Joe 的生成树中看到返回的生成树的 Neo4j Browser 可视化。

apoc.path.spanningTree.alicia denylist joe
图 10. 从 Alicia 开始,其中到达节点的路径不能经过 Joe 的生成树

关系类型序列

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

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

以下通过从 Joe 轮流遵循FOLLOWSKNOWS关系类型来返回可达节点
MATCH (p:Person {name: "Joe"})
CALL apoc.path.spanningTree(p, {
	relationshipFilter: "FOLLOWS>,KNOWS",
	beginSequenceAtStart: true,
	minLevel: 1,
	maxLevel: 4
})
YIELD path
RETURN path;

我们可以在从 Joe 开始,通过交替的FOLLOWSKNOWS关系类型的生成树中看到返回的生成树的 Neo4j Browser 可视化。

apoc.path.spanningTree.joe sequence
图 11. 从 Joe 开始,通过交替的FOLLOWSKNOWS关系类型的生成树
© . This site is unofficial and not affiliated with Neo4j, Inc.