匹配模式

匹配模式决定了关系在图模式匹配中是否可以多次出现(无论匹配模式如何,节点都可以多次出现)。Cypher® 支持两种匹配模式

  • DIFFERENT RELATIONSHIPS(不同关系):在给定的图模式匹配中,每个关系只能被遍历一次。此限制不适用于节点,节点在匹配路径中可以被多次重复遍历。这是 Cypher 的默认匹配模式,适用于大多数用例。

  • REPEATABLE ELEMENTS(可重复元素):对图模式匹配中节点和关系被遍历的次数没有限制。要使路径能够多次遍历同一个关系,必须使用此匹配模式。仅限 Cypher 25 在 Neo4j 2025.06 中引入

示例图

为了解释匹配模式,本页面将使用柯尼斯堡七桥问题作为场景。这是莱昂哈德·欧拉(Leonhard Euler)在 1736 年研究的一个问题,旨在确定一个人是否能在一次行走中恰好穿过柯尼斯堡的所有七座桥梁。

要重新创建该图,请在空的 Neo4j 数据库中运行以下查询

CREATE (kneiphof:Location {name: "Kneiphof"}),
       (northBank:Location {name: "North Bank"}),
       (southBank:Location {name: "South Bank"}),
       (lomse:Location {name: "Lomse"}),

       (kneiphof)-[:BRIDGE {id: 1}]->(northBank),
       (kneiphof)-[:BRIDGE {id: 6}]->(southBank),
       (kneiphof)-[:BRIDGE {id: 7}]->(lomse),
       (northBank)-[:BRIDGE {id: 5}]->(kneiphof),
       (northBank)-[:BRIDGE {id: 2}]->(lomse),
       (southBank)-[:BRIDGE {id: 4}]->(kneiphof),
       (southBank)-[:BRIDGE {id: 3}]->(lomse)

DIFFERENT RELATIONSHIPS

DIFFERENT RELATIONSHIPS 匹配模式确保在给定的 MATCH 结果中,每个关系只能出现一次,无论其遍历方向如何。同样的限制不适用于节点,节点在匹配中可以被多次遍历。因此,DIFFERENT RELATIONSHIPS 非常适合展示柯尼斯堡七桥问题:在图模型中,不遍历关系意味着不走那座桥,这是该问题的关键约束。

DIFFERENT RELATIONSHIPS 是 Cypher 的默认匹配模式。也就是说,如果未指定匹配模式,Cypher 将默认按照 DIFFERENT RELATIONSHIPS 施加的限制来求解图模式。

DIFFERENT RELATIONSHIPS 关键字于 Neo4j 2025.06 发布。它仅在 Cypher 25 中可用,可在 MATCH 后显式指定 Cypher 的默认匹配模式。例如,MATCH DIFFERENT RELATIONSHIPS p = (start)--{,2}(end)。这在功能上等同于不指定匹配模式。

为了展示 DIFFERENT RELATIONSHIPS 的行为,请考虑以下查询,它使用量化关系搜索距离起始 Location 节点 Kneiphof 恰好 5 跳的路径。此查询中使用的关系是有方向的,意味着路径是按照每座桥的特定方向遍历的(-[:BRIDGE]->)。

查找从起始节点出发长度为 5 个关系的路径
MATCH p = (:Location {name: 'Kneiphof'})-[:BRIDGE]->{5}()
RETURN [n IN nodes(p) | n.name] AS locations,
       [r IN relationships(p) | r.id] AS crossedBridges (1)
1 列表推导式遍历路径中的节点和关系,并返回特定属性(节点的 name 属性和关系的 id 属性)。

结果表明,节点可以在同一路径中被多次遍历,但关系(桥梁)绝不会被重复遍历(例如,路径 [6, 4, 1, 5, 6] 重复遍历了同一座桥,因此无法在 DIFFERENT RELATIONSHIPS 匹配模式下被匹配到)。

结果
locations crossedBridges

["Kneiphof", "North Bank", "Kneiphof", "South Bank", "Kneiphof", "Lomse"]

[1, 5, 6, 4, 7]

["Kneiphof", "South Bank", "Kneiphof", "North Bank", "Kneiphof", "Lomse"]

[6, 4, 1, 5, 7]

行:2

在下一个示例中,模式中移除了方向,并将路径长度增加到 6。结果显示有 48 条该长度的有效路径,其中没有关系(桥梁)被重复遍历。查询返回了其中一条路径作为 samplePath,展示了路径中遍历的所有节点和关系。

查找从起始节点出发长度为 6 个关系的路径
MATCH p = (:Location {name: 'Kneiphof'})-[:BRIDGE]-{6}()
WITH count(p) AS pathCount, collect(p)[0] AS samplePath (1)
ORDER BY pathCount
RETURN pathCount,
       [n IN nodes(samplePath) | n.name] AS samplePathLocations,
       [r IN relationships(samplePath) | r.id] AS samplePathBridges
1 collect() 函数收集所有路径,[0] 取第一项作为 samplePath
结果
pathCount samplePathLocations samplePathBridges

48

["Kneiphof", "North Bank", "Kneiphof", "South Bank", "Kneiphof", "Lomse", "North Bank"]

[1, 5, 6, 4, 7, 2]

行:1

DIFFERENT RELATIONSHIPS 返回的长度为 6samplePath 中,除了桥 3 之外,所有桥梁都被遍历了。

然而,如果将关系计数增加到 7,则返回 0 条路径。

查找长度为 7 个关系的路径
MATCH p = (:Location {name: 'Kneiphof'})--{7}()
RETURN count(p) AS pathCount
结果
pathCount

0

行:1

DIFFERENT RELATIONSHIPS 匹配模式下,每一步必须使用唯一的桥。第一步使用一座桥后,剩下六座桥供后续步骤使用。在遍历了第六座桥后,第七步将需要重复遍历某一座桥,这是不允许的。

这反映了欧拉柯尼斯堡七桥问题的结论:在一次行走中恰好穿过每座桥是不可能的。

有关此匹配模式的更多信息,请参阅 语法与语义 → DIFFERENT RELATIONSHIPS

REPEATABLE ELEMENTS

REPEATABLE ELEMENTS 匹配模式确保对于给定的 MATCH 结果,节点或关系出现的次数没有限制。因此,REPEATABLE ELEMENTS 匹配模式并不能解决在一次行走中恰好穿过柯尼斯堡每一座桥的不可能性问题。然而,能够重复遍历关系确实允许 Cypher 在测试欧拉假设时返回路径。

使用此匹配模式的查询必须在 MATCH 之后指定 REPEATABLE ELEMENTS 关键字。

以下查询使用 REPEATABLE ELEMENTS 匹配图中长度为 7 个关系的路径,并返回一条示例路径。

使用 REPEATABLE ELEMENTS 查找长度为 7 个关系的路径
MATCH REPEATABLE ELEMENTS p = (:Location {name: 'Kneiphof'})-[:BRIDGE]-{7}()
WITH collect(p)[0] AS samplePath
RETURN [n IN nodes(samplePath) | n.name] AS samplePathLocations,
       [r IN relationships(samplePath) | r.id] AS samplePathBridges
结果
samplePathLocations samplePathBridges

["Kneiphof", "North Bank", "Kneiphof", "North Bank", "Kneiphof", "North Bank", "Kneiphof", "North Bank"]

[1, 5, 1, 5, 1, 5, 1]

行:1

虽然使用 DIFFERENT RELATIONSHIPS 无法返回长度为 7 的路径,但该查询现在返回了一个 samplePath,展示了相同的两座桥(15)被重复遍历,直到达到最大路径长度。

下一个示例使用 REPEATABLE ELEMENTS 匹配模式,查找从同一个 Location (Kneiphof) 开始并结束的路径,且每座桥至少被穿过一次。

使用 REPEATABLE ELEMENTS 查找在返回起始 Location 之前遍历所有桥梁至少一次的路径
MATCH REPEATABLE ELEMENTS p = (start:Location {name: 'Kneiphof'})-[:BRIDGE]-{,9}(start) (1)
WHERE all(bridge IN range(1,7) WHERE bridge IN [r IN relationships(p) | r.id]) (2)
RETURN [n IN nodes(p) | n.name] AS visitedLocations,
       [r IN relationships(p) | r.id] AS crossedBridges
ORDER BY length(p), crossedBridges
LIMIT 1
1 长度小于 9 个关系的路径不会返回任何结果,因为它们没有足够的步数在形成回到 Kneiphof 的闭环的同时,将所有七座桥至少遍历一次。
2 all() 函数确保路径中每一座桥都必须被遍历过一次。
结果
visitedLocations crossedBridges

["Kneiphof", "North Bank", "Kneiphof", "South Bank", "Lomse", "North Bank", "Kneiphof", "South Bank", "Lomse", "Kneiphof"]

[1, 1, 4, 3, 2, 5, 6, 3, 7]

行:1

返回路径中遍历桥梁的顺序表明,桥 13 被穿过了两次,以便返回 Kneiphof

使用 REPEATABLE ELEMENTS 时遍历桥梁的顺序。

有关此匹配模式的更多信息,请参阅 语法与语义 → REPEATABLE ELEMENTS

有界路径长度

使用 DIFFERENT RELATIONSHIPS 时,返回的路径数量是有限的,因为关系不能被重复遍历。然而,由于 REPEATABLE ELEMENTS 允许重复遍历关系,它支持完整的循环遍历和可以折回的路径。因此,REPEATABLE ELEMENTS 可能会生成非常巨大甚至无限数量的有效路径。

下面的查询显示,使用 REPEATABLE ELEMENTSKneiphof 开始,长度为 7 个关系的有效路径有 10583 条。

使用 REPEATABLE ELEMENTS 计算遍历所有 7 座桥至少一次的路径数量
MATCH REPEATABLE ELEMENTS p = (:Location {name: 'Kneiphof'})-[:BRIDGE]-{7}()
RETURN count(p) AS pathCount
结果
pathCount

10583

行:1

如果路径长度增加到正好 10,总共会返回 490047 条路径;11 跳会返回 1818159 条路径;12 跳会返回 6498397 条路径,以此类推,没有限制。

为了确保 MATCH 能在有限时间内返回有限数量的解决方案,不允许在 REPEATABLE ELEMENTS 中结合使用不强制模式上限的无界量词,例如 *+{1,}。此外,用户应考虑到,对于大量重复返回的结果数量,可能会显著影响内存使用量和查询速度。

不允许:使用 REPEATABLE ELEMENTS 查找无界长度的路径
MATCH REPEATABLE ELEMENTS p = (start:Location {name: 'Kneiphof'})-[:BRIDGE]-+(start)
WHERE all(bridge IN range(1,7) WHERE bridge IN [r IN relationships(p) | r.id])
RETURN count(p) AS pathCount
GQLSTATUS 错误链

42N53: 错误: 语法错误或访问规则违规 - 不安全地使用可重复元素。在 'REPEATABLE ELEMENTS' 匹配模式下,该量化路径模式可能会产生无限数量的行。请为量化路径模式添加上限。

42001:错误:语法错误或访问规则冲突 - 无效语法