知识库

关于 OPTIONAL MATCH 的说明

OPTIONAL MATCH 像 MATCH 一样在图数据库中匹配模式。不同之处在于,如果没有找到匹配项,OPTIONAL MATCH 会为模式中缺失的部分使用 null。OPTIONAL MATCH 可视为 Cypher 中对应于 SQL 外连接的操作。

了解这一点后,可以这样编写 Cypher 查询

OPTIONAL MATCH (actor:Actor)-[:ACTED_IN]->(:Movie)<-[:DIRECTED]-(director:Director {uuid:'fd787f45-df1a-4f8b-b4a9-ab7b90fefae4'})
OPTIONAL MATCH (director)-[:HAS_STUDIO*2]->(:Studio)-[:HAS_ACTOR]->(actor)-[:HAS_PROFILE]->(profile:Profile)
WHERE profile.type IN ["Drama", "Action"]
MERGE (director)-[:HAS]->(actor)
ON CREATE SET profile.uuid = apoc.create.uuid(), profile.lastTimeReported = '2018-12-15T23:13:22.274', profile.reportingState = 'Active'
ON MATCH SET profile.lastTimeReported = '2018-07-15T23:30:00.000', profile.reportingState = 'Active'
RETURN COUNT(profile) as updatedCount

然而,这个查询可能会返回类似以下的错误

Neo.DatabaseError.General.UnknownError: org.neo4j.values.storable.NoValue cannot be cast to org.neo4j.values.virtual.VirtualNodeValue

(pre 3.4.5)

Neo.DatabaseError.Statement.ExecutionFailed: Expected to find a node at ref slot 0 but found instead: null

(post 3.4.5)

这是因为以 OPTIONAL MATCH 开头的查询并不总是与 Neo4j 配合良好,尤其是当你的 OPTIONAL MATCH 未返回任何值且影响后续查询计划时。最简单的触发此问题的查询形式如下,在空数据库上运行时会出现此情况。

OPTIONAL MATCH (a)
MERGE (a)-[:X]->()

在这些情况下抛出的信息如下

Expected to find a node at $name but found instead: null
Expected to find a node at $name but found instead: $x
Expected to find a node at $name but found instead: null

当遇到上述信息之一时,问题与 OPTIONAL MATCH 有关,可通过使用普通的 MATCH 开头查询来解决,例如

MATCH (actor:Actor)-[:ACTED_IN]->(:Movie)<-[:DIRECTED]-(director:Director {uuid:'fd787f45-df1a-4f8b-b4a9-ab7b90fefae4'})
OPTIONAL MATCH (director)-[:HAS_STUDIO*2]->(:Studio)-[:HAS_ACTOR]->(actor)-[:HAS_PROFILE]->(profile:Profile)
WHERE profile.type IN ["Drama", "Action"]
MERGE (director)-[:HAS]->(actor)
ON CREATE SET profile.uuid = apoc.create.uuid(), profile.lastTimeReported = '2018-12-15T23:13:22.274', profile.reportingState = 'Active'
ON MATCH SET profile.lastTimeReported = '2018-07-15T23:30:00.000', profile.reportingState = 'Active'
RETURN COUNT(profile) as updatedCount

如果你的 OPTIONAL MATCH 较长,建议将其拆分为(至少)一个 MATCH,随后跟随 OPTIONAL MATCH(们)。应当先 MATCH 那些 必须存在 的部分,然后对 可能不存在 的模式片段使用 OPTIONAL MATCH(们)。

对于上面的示例,需要保留第一行中的完整模式,因为我们至少需要导演及其演员。在其他情况下,可能只需要一个起始节点。经验法则是先使用 MATCH 捕获 所需的最小图部分,然后对 其它可选的 部分使用 OPTIONAL MATCH(们)。

© . This site is unofficial and not affiliated with Neo4j, Inc.