【发布时间】: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
【问题讨论】: