Neo4j:应用索引和约束更改查询结果

Neo4j: Applying index and constraint changes query results

我遇到了 Neo4j 的问题,在应用以下内容后,相同查询的结果发生了变化:

环境

重现步骤:

通过运行以下内容创建一组节点和关系:

CREATE (p1:Person { id: '100', name: 'Hampton Fancher' })<-[:WRITTEN_BY]-(m:Movie { id: '101', name: 'Blade Runner' })-[:BASED_ON]->(n:Novel { id: '102', name: 'Do Androids Dream of Electric Sheep?' })-[:WRITTEN_BY]->(p2:Person { id: '103', name: 'Philip K Dick' })

通过 运行 以下内容创建第二组节点和关系:

CREATE (p1:Person { id: '200', name: 'Phil Alden Robinson' })<-[:WRITTEN_BY]-(m:Movie { id: '201', name: 'Field of Dreams' })-[:BASED_ON]->(n:Novel { id: '202', name: 'Shoeless Joe' })-[:WRITTEN_BY]->(p2:Person { id: '203', name: 'W P Kinsella' })

运行 这个查询:

MATCH (movie:Movie { name: 'Blade Runner' })

OPTIONAL MATCH (movie)-[:WRITTEN_BY|BASED_ON]->(entity)
    WHERE entity:Person OR entity:Novel

OPTIONAL MATCH (entity:Novel)-[:WRITTEN_BY]->(sourceNovelWriter:Person)

RETURN sourceNovelWriter

结果符合预期(即它们反映了 Philip K Dick 作为 Blade 运行ner 的源小说作家):

╒═══════════════════════════════════╕
│"sourceNovelWriter"                │
╞═══════════════════════════════════╡
│{"name":"Philip K Dick","id":"103"}│
├───────────────────────────────────┤
│null                               │
└───────────────────────────────────┘

然后为带有 Novel 标签的节点 name 属性 创建一个索引:

CREATE INDEX ON :Novel(name)

然后为带有 Novel 标签的节点创建 name 属性 的存在约束:

CREATE CONSTRAINT ON (n:Novel) ASSERT EXISTS(n.name)

N.B。以下行为仅在同时应用索引和约束时才会出现;如果只应用一个,则不会发生。

Re-运行 初始查询显示结果已更改为如下所示,这不是预期的(即他们错误地指出 W P Kinsella 是 Blade 运行 的源小说作者内尔):

╒═══════════════════════════════════╕
│"sourceNovelWriter"                │
╞═══════════════════════════════════╡
│{"name":"Philip K Dick","id":"103"}│
├───────────────────────────────────┤
│{"name":"W P Kinsella","id":"203"} │
├───────────────────────────────────┤
│{"name":"Philip K Dick","id":"103"}│
├───────────────────────────────────┤
│{"name":"W P Kinsella","id":"203"} │
└───────────────────────────────────┘

可以通过从第二个 OPTIONAL MATCH 中删除 Novel 标签来修复查询(但最好是更明确地表达只有在 entity 变量有一个 Novel 标签):

MATCH (movie:Movie { name: 'Blade Runner' })

OPTIONAL MATCH (movie)-[:WRITTEN_BY|BASED_ON]->(entity)
    WHERE entity:Person OR entity:Novel

OPTIONAL MATCH (entity)-[:WRITTEN_BY]->(sourceNovelWriter:Person)

RETURN sourceNovelWriter

这个returns:

╒═══════════════════════════════════╕
│"sourceNovelWriter"                │
╞═══════════════════════════════════╡
│{"name":"Philip K Dick","id":"103"}│
├───────────────────────────────────┤
│null                               │
└───────────────────────────────────┘

可以通过修改查询使其成为 return 值来检查 entity 变量:

MATCH (movie:Movie { name: 'Blade Runner' })

OPTIONAL MATCH (movie)-[:WRITTEN_BY|BASED_ON]->(entity)
    WHERE entity:Person OR entity:Novel

OPTIONAL MATCH (entity:Novel)-[:WRITTEN_BY]->(sourceNovelWriter:Person)

RETURN entity

结果中错误地包含了 Shoeless Joe

╒══════════════════════════════════════════════════════════╕
│"entity"                                                  │
╞══════════════════════════════════════════════════════════╡
│{"name":"Do Androids Dream of Electric Sheep?","id":"102"}│
├──────────────────────────────────────────────────────────┤
│{"name":"Shoeless Joe","id":"202"}                        │
├──────────────────────────────────────────────────────────┤
│{"name":"Do Androids Dream of Electric Sheep?","id":"102"}│
├──────────────────────────────────────────────────────────┤
│{"name":"Shoeless Joe","id":"202"}                        │
└──────────────────────────────────────────────────────────┘

如果去掉第二个OPTIONAL MATCH,即

MATCH (movie:Movie { name: 'Blade Runner' })

OPTIONAL MATCH (movie)-[:WRITTEN_BY|BASED_ON]->(entity)
    WHERE entity:Person OR entity:Novel

RETURN entity

然后 returned entity 正确地与 Blade 运行ner:

╒══════════════════════════════════════════════════════════╕
│"entity"                                                  │
╞══════════════════════════════════════════════════════════╡
│{"name":"Do Androids Dream of Electric Sheep?","id":"102"}│
├──────────────────────────────────────────────────────────┤
│{"name":"Hampton Fancher","id":"100"}                     │
└──────────────────────────────────────────────────────────┘

似乎 entity 变量在第二个 OPTIONAL MATCH 中重置,但只有在设置索引和约束条件时才重置。

这是预料之中的吗?是什么导致了这种行为?

提前致谢。

是的,这是对 Neo4j 4.2.3 中修复的错误的一个很好的说明,当标签出现在先前绑定变量的可选匹配中时会发生。

来自更新日志:

Fixed a bug where an index scan would be used to solve an OPTIONAL MATCH incorrectly.

https://github.com/neo4j/neo4j/wiki/Neo4j-4.2-changelog#423

修复之前的解决方法是删除冗余标签。

我们强烈建议您至少更新到您的次要版本的最新补丁,以避免已知和已修复的错误。