NEO4J Optional Match when null, 整个查询返回为空
Posted
技术标签:
【中文标题】NEO4J Optional Match when null, 整个查询返回为空【英文标题】:NEO4J Optional Match when null, entire query return is empty 【发布时间】:2018-04-06 10:33:45 【问题描述】:我在一个有多个可选匹配项的查询中遇到 null 结果问题。
//Match gs to searched w
MATCH (w1:W name: "****")-[:REL]->(gs:G)
WITH w1, COLLECT(DISTINCT gs) AS gsCol, SIZE((w1)-[:REL]-()) AS gCount
OPTIONAL MATCH (w1)-[:REL]-()-[:SIMILAR*0..1]->(gs:G)
WITH w1, gsCol, gCount, COLLECT(DISTINCT gs) AS similarGs
//Match all ws that contain gs in searched w or where similar as wsCol
OPTIONAL MATCH (w1)-[c2a:REL]->(g4:G)-[c2b:REL|:SIMILAR*0..1]-(ws:W)
WHERE c2a.amount - 10 < last(c2b).amount < c2a.amount + 10
WITH w1, gsCol, similarGs, gCount, COLLECT(DISTINCT ws) AS ws2, COLLECT(DISTINCT ws) AS ws3, COLLECT(DISTINCT ws) AS ws4
//Match ws from wsCol where all gs in new matched ws are same
UNWIND ws2 as w2
OPTIONAL MATCH (w2)-[c3:REL]->(g3:G)
WITH w1, w2, ws3, ws4, gsCol, similarGs, gCount, COLLECT(g3) AS gs3, SIZE((w2)-[:REL]->()) as gCount3, SUM(c3.amount) AS c3amount
WHERE ALL(x in gs3 WHERE x IN gsCol)
WITH w1, w2, ws3, ws4, gsCol, similarGs, gCount, gCount3, c3amount
WHERE gCount3 = gCount AND c3amount = 100
WITH COLLECT(w2) AS ws2Col, w1, ws3, ws4, gsCol, similarGs, gCount
//Match ws with gs that are in searched or similar to searched w
UNWIND ws3 as w3
WITH w1, w3, ws4, gsCol, similarGs, gCount, ws2Col
OPTIONAL MATCH (w3)-[c4:REL]->(g4:G)
WITH w1, w3, ws4, ws2Col, gsCol, similarGs, gCount, COLLECT(g4) AS gs4, SIZE((w3)-[:REL]->()) AS gCount4, SUM(c4.amount) AS c4amount
WHERE ALL(x in gs4 WHERE x in similarGs)
WITH w1, w3, ws4, ws2Col, gsCol, similarGs, gCount, gs4, gCount4
WHERE gCount4 = gCount AND c4amount = 100 AND NOT(w3 IN ws2Col)
WITH COLLECT(w3) AS ws3Col, w1, w3, ws4, ws2Col, gsCol, gCount, similarGs
//Match ws where depending on number of gs in w 1 or 2+ gs match searched w
UNWIND ws4 AS w4
OPTIONAL MATCH (w4)-[c5b:REL]->(g5:G)
WITH w1, w4, ws2Col, ws3Col, gsCol, similarGs, gCount, sum(c5b.amount) AS c6amount, SIZE((w4)-[:REL]-()) as gCount5, collect(g5) AS gs5, max(c5b.amount) as c6max
WHERE ALL(x IN gs5 WHERE x IN gsCol) AND (CASE WHEN gCount > 2 THEN c6amount > 25 ELSE c6amount > 65 END) AND NOT(w4 in ws2Col) AND NOT(w4 in ws3Col)
WITH COLLECT(w4) AS ws4Col, w1, ws2Col, ws3Col, w4, gsCol, similarGs, gCount, c6amount, gCount5, gs5, c6max
UNWIND ws2Col AS ws2a UNWIND ws3Col AS ws3a UNWIND ws4Col AS ws4a
RETURN collect(distinct ws2a) AS match1, collect(distinct ws3a) AS match2, collect(distinct ws4a) AS match3
在此查询中有时 w2、w3 或 w4 可以返回 null,这是预期的行为,但是当其中任何一个为 null 时,整个结果为 null 或
╒════════╤════════╤════════╕
│"match1"│"match2"│"match3"│
╞════════╪════════╪════════╡
│[] │[] │[] │
└────────┴────────┴────────┘
如果 match2 为空,我希望在 match1 和/或 match3 中看到一些结果。
我尝试在不使用 collect(w2)、collect(w3) 和 collect(w4) 的情况下运行查询,但这只会导致查询超时或耗尽堆大小。
谁能建议一种方法来避免可选匹配返回 null 删除查询中的所有内容或为其他可选匹配返回 null?
编辑 1 --
已找到查询可能中断的点...在可选匹配的第二个位置..
AND NOT(w3 IN ws2Col)
即使此时我运行 return,如果 w3 为 null,ws2Col 也会返回 null
编辑 2 --
@BrunoPeres 的答案几乎就在那里,并朝着更接近的方向迈出了一大步。如果其他集合之一为空,则必须将第二个和第三个 COLLECT
更改为 FILTER
以使查询不删除这些集合。这是可能遇到此问题的人的最终查询。
//Match gs to searched w
MATCH (w1:W name: "****")-[:CONTAINS]->(gs:G)
WITH w1, COLLECT(DISTINCT gs) AS gsCol, SIZE((w1)-[:CONTAINS]-()) AS gCount
OPTIONAL MATCH (w1)-[:CONTAINS]-()-[:SIMILAR*0..1]->(gs:G)
WITH w1, gsCol, gCount, COLLECT(DISTINCT gs) AS similarGs
//Match all ws that contain gs in searched w or where similar as wsCol
OPTIONAL MATCH (w1)-[c2a:CONTAINS]->(g4:G)-[c2b:CONTAINS|:SIMILAR*0..1]-(ws:W)
WHERE c2a.amount - 10 < last(c2b).amount < c2a.amount + 10
WITH w1, gsCol, similarGs, gCount, COLLECT(DISTINCT ws) AS ws2, COLLECT(DISTINCT ws) AS ws3, COLLECT(DISTINCT ws) AS ws4
//Match ws from wsCol where all gs in new matched ws are same
UNWIND ws2 as w2
OPTIONAL MATCH (w2)-[c3:CONTAINS]->(g3:G)
WITH w1, w2, ws3, ws4, gsCol, similarGs, gCount, COLLECT(g3) AS gs3, SIZE((w2)-[:CONTAINS]->()) as gCount3, SUM(c3.amount) AS c3amount
WHERE ALL(x in gs3 WHERE x IN gsCol)
WITH w1, w2, ws3, ws4, gsCol, similarGs, gCount, gCount3, c3amount
WHERE gCount3 = gCount AND c3amount = 100
WITH COLLECT(w2) ELSE ['none'] END AS ws2Col, w1, ws3, ws4, gsCol, similarGs, gCount
//Match ws with gs that are in searched or similar to searched w
UNWIND ws3 as w3
WITH w1, w3, ws4, gsCol, similarGs, gCount, ws2Col
OPTIONAL MATCH (w3)-[c4:CONTAINS]->(g4:G)
WITH w1, w3, ws4, ws2Col, gsCol, similarGs, gCount, COLLECT(g4) AS gs4, SIZE((w3)-[:CONTAINS]->()) AS gCount4, SUM(c4.amount) AS c4amount
WHERE ALL(x in gs4 WHERE x in similarGs)
WITH w1, w3, ws4, ws2Col, gsCol, similarGs, gCount, gs4, gCount4, c4amount
WHERE gCount4 = gCount AND c4amount = 100 AND NOT(w3 IS NULL OR w3 IN ws2Col)
WITH CASE WHEN NOT(w3 IS NULL) THEN COLLECT(w3) ELSE ['none'] END AS ws3Col, w1, w3, ws4, ws2Col, gsCol, gCount, similarGs
//Match ws where depending on number of gs in w 1 or 2+ gs match searched w
UNWIND ws4 AS w4
OPTIONAL MATCH (w4)-[c5b:CONTAINS]->(g5:G)
WITH w1, w4, ws2Col, ws3Col, gsCol, similarGs, gCount, sum(c5b.amount) AS c6amount, SIZE((w4)-[:CONTAINS]-()) as gCount5, collect(g5) AS gs5, max(c5b.amount) as c6max, ws2Col + ws3Col AS wsC
WHERE ALL(x IN gs5 WHERE x IN gsCol) AND (CASE WHEN gCount > 2 THEN c6amount > 25 ELSE c6amount > 65 END) AND NOT(w4 in ws2Col OR w4 in ws3Col)
WITH CASE WHEN w4 IS NULL THEN ['none'] ELSE COLLECT(w4) END AS ws4Col, w1, ws2Col, ws3Col, w4, gsCol, similarGs, gCount, c6amount, gCount5, gs5, c6max
// Return results
UNWIND (CASE ws2Col WHEN [] THEN [null] ELSE ws2Col END) AS ws2a
UNWIND (CASE ws3Col WHEN [] THEN [null] ELSE ws3Col END) AS ws3a
UNWIND (CASE ws4Col WHEN [] THEN [null] ELSE ws4Col END) AS ws4a
RETURN collect(distinct ws2a) AS match1, collect(distinct ws3a) AS match2, collect(distinct ws4a) AS match3
【问题讨论】:
【参考方案1】:根据文档The in operator and null,当您测试null
是否为IN
给定列表时,返回将是null
:
所以下面表达式的返回将为空:
RETURN null IN [1, 2, 3]
╒═══════════════════╕
│"null IN [1, 2, 3]"│
╞═══════════════════╡
│null │
└───────────────────┘
因此,表达式NOT(null IN [1, 2, 3])
的返回也将为空。
我认为您可以修复您的查询,将您的测试更改为:
AND NOT(w3 IS NULL OR w3 IN ws2Col)
即:当w3
为null
时,它不被视为列表的元素。
【讨论】:
仍然返回空的所有内容,但它确实保留了 ws2Col 在这一点上......所以我们更近了一步。现在要找到一种使用该 null 的方法来进行实际有效的收集。已经尝试过 CASE WHEN xxxx THEN ['none'] AS ... 与以下.... w3 IS NULL, w3 IS NOT NULL, w3Count = 0 (尝试在收集之前的附加 WITH 子句中添加 count(w3) ) @DaveClissold 看看coalesce function。我认为它可以帮助你。 谢谢。现在,当我到达最终的可选匹配时,它会删除 ws2Col 和 ws3Col 的值,如果 WHERE 查询AND NOT(w4 IS NULL OR w4 in ws2Col or w4 in ws3Col)
返回 null,则在此点之后立即尝试中断并仅返回 ws2Col 和 ws3Col 但什么也没有。有什么想法吗?
@DaveClissold ws2Col
和 ws3Col
都不为空?
是的,两者都不为空以上是关于NEO4J Optional Match when null, 整个查询返回为空的主要内容,如果未能解决你的问题,请参考以下文章
在 CREATE 和 MATCH 之间需要 Neo4j Cypher WITH