OPTIONAL MATCH

简介

OPTIONAL MATCHMATCH 一样,在图数据库中匹配模式。不同之处在于,如果没有找到匹配项,OPTIONAL MATCH 将对模式中缺失的部分使用 null。因此,OPTIONAL MATCH 可以被视为 Cypher® 中等同于 SQL 外连接(outer join)的语法。

在使用 OPTIONAL MATCH 时,要么匹配整个模式,要么什么都不匹配。WHERE 子句是模式描述的一部分,其谓词将在寻找匹配项时(而不是之后)被考量。这一点在存在多个 (OPTIONAL) MATCH 子句时尤为重要,必须将 WHERE 与其所属的 MATCH 放在一起。

示例图

以下图表用于下方的示例

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

CREATE
  (charlie:Person {name: 'Charlie Sheen'}),
  (martin:Person {name: 'Martin Sheen'}),
  (michael:Person {name: 'Michael Douglas'}),
  (oliver:Person {name: 'Oliver Stone'}),
  (rob:Person {name: 'Rob Reiner'}),
  (wallStreet:Movie {title: 'Wall Street'}),
  (charlie)-[:ACTED_IN]->(wallStreet),
  (martin)-[:ACTED_IN]->(wallStreet),
  (michael)-[:ACTED_IN]->(wallStreet),
  (oliver)-[:DIRECTED]->(wallStreet),
  (thePresident:Movie {title: 'The American President'}),
  (martin)-[:ACTED_IN]->(thePresident),
  (michael)-[:ACTED_IN]->(thePresident),
  (rob)-[:DIRECTED]->(thePresident),
  (martin)-[:FATHER_OF]->(charlie)

深入了解 OPTIONAL MATCH

与 SQL 一样,Cypher 查询由多个子句构成,这些子句链接在一起以在彼此之间传递中间结果。例如,来自一个 MATCH 子句的匹配变量将为后续子句提供存在的上下文。然而,Neo4j 与 SQL 之间有两个重要的区别,有助于进一步解释 OPTIONAL MATCH

  1. 虽然通过索引和约束来强制实施部分模式既可行也被推荐,但与关系型数据库相比,Neo4j 提供了更高程度的模式灵活性。Neo4j 数据库中的节点和关系不必因为同一图中的其他节点或关系具有某种属性,自身就必须拥有该属性(除非在特定属性上创建了属性存在性约束)。

  2. Cypher 中的查询是作为流水线运行的。如果一个子句没有返回结果,它将有效地结束查询,因为后续子句将没有数据可执行。

例如,以下查询不返回任何结果

MATCH (a:Person {name: 'Martin Sheen'})
MATCH (a)-[r:DIRECTED]->()
RETURN a.name, r
(no changes, no records)

这是因为第二个 MATCH 子句没有返回数据(图中没有连接到 Martin SheenDIRECTED 关系)传递给 RETURN 子句。

然而,将第二个 MATCH 子句替换为 OPTIONAL MATCH 则会返回结果。这是因为与 MATCH 不同,OPTIONAL MATCH 允许在子句之间传递 null 值。

MATCH (p:Person {name: 'Martin Sheen'})
OPTIONAL MATCH (p)-[r:DIRECTED]->()
RETURN p.name, r
结果
p.name r

"Martin Sheen"

<null>

行:1

因此,OPTIONAL MATCH 可用于在图中检查缺失值和现有值,并允许在不带任何数据的情况下将行传递给查询中的后续子句。

可选关系

如果关系的存在是可选的,请使用 OPTIONAL MATCH 子句。如果关系存在,则返回该关系。如果不存在,则返回 null 以代替。

MATCH (a:Movie {title: 'Wall Street'})
OPTIONAL MATCH (a)-->(x)
RETURN x

返回 null,因为 Movie 节点 Wall Street 没有出站关系。

结果
x

<null>

行:1

另一方面,以下查询不会返回 null,因为 Person 节点 Charlie Sheen 有一个出站关系。

MATCH (a:Person {name: 'Charlie Sheen'})
OPTIONAL MATCH (a)-->(x)
RETURN x
结果
x

{"title":"Wall Street"}

行:2

可选元素的属性

如果属性的存在是可选的,请使用 OPTIONAL MATCH 子句。如果指定的属性不存在,将返回 null

MATCH (a:Movie {title: 'Wall Street'})
OPTIONAL MATCH (a)-->(x)
RETURN x, x.name

返回元素 x(在本查询中为 null),并为其 name 属性返回 null,因为 Movie 节点 Wall Street 没有出站关系。

结果
x x.name

<null>

<null>

行:1

以下查询仅为缺少 name 属性的节点返回 null

MATCH (a:Person {name: 'Martin Sheen'})
OPTIONAL MATCH (a)-->(x)
RETURN x, x.name
结果
x x.name

{"title":"Wall Street"}

<null>

{"name":"Charlie Sheen"}

"Charlie Sheen"

{"title":"The American President"}

<null>

行:3

可选的类型化和命名关系

使用 OPTIONAL MATCH 时,也可以查找特定的关系类型

MATCH (a:Movie {title: 'Wall Street'})
OPTIONAL MATCH (a)-[r:ACTED_IN]->()
RETURN a.title, r

这返回 Movie 节点 Wall Street 的标题,由于该节点没有出站的 ACTED_IN 关系,因此变量 r 所代表的关系返回 null

结果
a.title r

"Wall Street"

<null>

行:1

然而,以下查询不会返回 null,因为它正在查找指向 Movie 节点 Wall StreetACTED_IN 类型的入站关系。

MATCH (a:Movie {title: 'Wall Street'})
OPTIONAL MATCH (x)-[r:ACTED_IN]->(a)
RETURN a.title, x.name, type(r)
结果
a.title x.name type(r)

"Wall Street"

"Michael Douglas"

"ACTED_IN"

"Wall Street"

"Martin Sheen"

"ACTED_IN"

"Wall Street"

"Charlie Sheen"

"ACTED_IN"

行:3