【问题标题】:Unexpected behavior combining collections in Cypher在 Cypher 中组合集合的意外行为
【发布时间】:2017-02-13 21:31:16
【问题描述】:

使用http://console.neo4j.org 作为沙箱,我遇到了以下意外行为:

语句 1 - 返回 1 行,其中包含一个包含 Neo 节点的集合

MATCH (n:Crew) 
WHERE n.name="Neo" 
WITH COLLECT(n) AS c1
WITH c1+[] AS c2
RETURN c2

语句 2 - 返回 0 行(意外)

MATCH (n:Crew) 
WHERE n.name="Neo" 
WITH COLLECT(n) AS c1
MATCH (n:Crew) 
WHERE n.name="NoOne"
WITH c1+COLLECT(n) AS c2
RETURN c2

语句 3 - 返回包含空集合的 1 行

MATCH (n:Crew) 
WHERE n.name="NoOne"
WITH COLLECT(n) AS c1
RETURN c1

我不明白为什么 Statement 2 没有返回与 Statement 1 相同的结果,因为它应该返回一个包含 Neo 节点的集合,就像在 语句 1
语句 3 表明 语句 2 中的第二个 MATCH 应该是一个空集合。

这种行为在 Cypher 中是预期的吗?如果是这种情况,我很乐意提供一个小解释来帮助我理解这种行为。

【问题讨论】:

  • 在语句2中使用可选匹配,如果MATCH没有返回数据,那么(除非你有一个ONLY聚合结果)它不会返回任何行

标签: neo4j cypher


【解决方案1】:

对于为什么第二个查询没有达到您的预期,我想不出正确的解释,但是如果您有多个要链接在一起的可选匹配项,那么您可以使用 OPTIONAL MATCH 来做到这一点:

OPTIONAL MATCH (n:Crew) 
WHERE n.name="Neo" 
WITH COLLECT(n) AS c1
OPTIONAL MATCH (n:Crew) 
WHERE n.name="NoOne"
WITH c1+COLLECT(n) AS c2
RETURN c2

【讨论】:

    【解决方案2】:

    我以前遇到过这种确切的行为,这非常令人沮丧。问题在于查询 2 中的第二个 MATCH 子句:如果现有的结果行(在这种情况下,是带有 c1 的单行)没有为 MATCH 返回任何结果,则该行将被完全删除在 MATCH 子句之后,即使 MATCH 本身(没有预先存在的结果行)返回一个空集合。如果您将其转换为 OPTIONAL MATCH,您将能够在没有匹配项时保留结果行。

    更新:请参阅下文以获得更全面的分析,但要注意的是,语句 2 中的第二个 COLLECT(n)确实返回一个空列表,就像在语句 3 中一样;但是,整个子句 WITH c1+COLLECT(n) AS c2 不返回任何行,因为在第二个 MATCH 之后没有具有 c1 值的行。

    【讨论】:

    • 如果 Neo 的某个人没有发表评论,我建议在 GitHub 上提出问题。它看起来确实是关于聚合的不一致行为。
    • 我不认为这是不一致的聚合行为;如果您从查询 2 的第二个 WITH 语句中删除 c1+,您将再次获得一个包含空集合的单行。查询 2 中的WITH 语句如所写 需要具有c1 值的行来生成一个新的结果行,其中它有0,而查询3 从不需要现有的结果行。
    • 如果你删除中间的WITH(所以只需堆叠两个MATCH 语句,然后在一个COLLECTS 中执行两个WITH statement)你最终会得到一个空列表(因为没有一行适合MATCHes)。所以聚合行为是自洽的,是WITH 导致了这里的问题。
    最近更新 更多