2017-02-18 21 views
1

這是一個後續問題:如何要求的Neo4j把週期考慮以優化的方式

How to ask Neo4j to take cycles into account

在我剛纔的問題,@ stdob--好心幫我找到下面的查詢:

MATCH (n1:S) 
OPTIONAL MATCH (n1)-[:R]->(n2:R)<-[:R]-(n3:E) 
OPTIONAL MATCH (n3t)-[:R]->(n4:R:L) 
WHERE n3t = n3 
RETURN labels(n1), labels(n3t), labels(n4); 

上述查詢是以下替換:

MATCH (n1:S) 
OPTIONAL MATCH (n1)-[:R]->(n2:R)<-[:R]-(n3:E)-[:R]->(n4:R:L) 
RETURN labels(n1), labels(n3t), labels(n4); 

我必須使用第一個,因爲在我的數據中可能有n2n4是相同的節點,並且由於Neo4j拒絕同一個節點兩次,它將返回null。

雖然第一個查詢是有效的並且工作正常,但它的性能非常糟糕。它強制數據庫重新開始搜索整個數據,最後它將使用n3t = n3匹配所選節點。只是爲了給您一個提示其性能有多糟糕的提示,對於200k大小的數據集,返回結果需要5秒鐘,而如果我省略第二個OPTIONAL MATCH及其WHERE,則結果對於相同的結果在少於10毫秒內生成查詢。如果任何人的興趣,下面是用於查詢執行計劃:

enter image description here

分支,在右側是我剛纔提到的部分(我試圖愚弄的Neo4j採取第二次節點)。正如你所看到的,爲了使Neo4j第二次獲得一個節點,發生了2M分貝命中。該執行計劃的實際查詢爲:

PROFILE MATCH (n5_1:Revision:`Account`)<-[:RevisionOf]-(n5_2:Entity:`Account`) 
WITH n5_2, n5_1 
ORDER BY n5_1.customer_number ASC 
LIMIT 100 
OPTIONAL MATCH (n5_1)-[:`Main Contact`]->(n4_1:Wrapper)<-[:Wrapper]-(:Revision:`Contact`)<-[:RevisionOf]-(n4_2:Entity:`Contact`) 
OPTIONAL MATCH (n4_4)-[:RevisionOf]->(n4_3:Revision:Latest:`Contact`:Active) 
WHERE (n4_2) = (n4_4) 
RETURN n5_1, n5_2, n4_1, n4_2, n4_3 

所以我的問題是,我怎麼能寫在其中一個節點採取第二次,而性能不會再遭受的Cypher查詢?

對於某些示例數據和測試牀,請轉到其他問題。

+1

您是否考慮爲此編寫自定義過程?您可能需要查看APOC [PathExplorer]的代碼(https://github.com/neo4j-contrib/neo4j-apoc-procedures/blob/3。1/src/main/java/apoc/path/PathExplorer.java)作爲起點。這將使您更好地控制遍歷唯一性,允許您在遍歷期間重用邊緣。 – InverseFalcon

+0

你最近的OPTIONAL MATCH有點奇怪,因爲你在這裏使用了一個新的變量'n4_4',但是在你說它必須等於'n4_2'後你有一個where子句。這種可選匹配是您擊中性能的原因。如果你在這場比賽中使用'n4_2',它應該可以工作。然而,在你的鏈接問題中,這給出了一些不希望的結果,但它看起來應該很容易過濾你必須確保'n_43'不爲空的結果。 – InverseFalcon

回答

1

我對你的鏈接的問題張貼解答,應該給你描述的結果表。如果適合你在找什麼,這個查詢使用相同的方法,並且可能是這個問題的解決方案:

PROFILE MATCH (n5_1:Revision:`Account`)<-[:RevisionOf]-(n5_2:Entity:`Account`) 
WITH n5_2, n5_1 
ORDER BY n5_1.customer_number ASC 
LIMIT 100 
OPTIONAL MATCH (n5_1)-[:`Main Contact`]->(n4_1:Wrapper)<-[:Wrapper]-(:Revision:`Contact`)<-[:RevisionOf]-(n4_2:Entity:`Contact`) 
WHERE (n4_2)-[:RevisionOf]->(:Revision:Latest:`Contact`:Active) 
OPTIONAL MATCH (n4_2)-[:RevisionOf]->(n4_3:Revision:Latest:`Contact`:Active) 
RETURN n5_1, n5_2, n4_1, n4_2, n4_3 

這樣可以使你的最後一個可選匹配n4_2,這應該能夠解決性能問題,你觀察到的。

正如您在上一個問題中所述,您希望避免第一個OPTIONAL MATCH成功但第二個失敗的情況,當您不希望它們成爲第一個OPTIONAL MATCH時,將變量保留爲非空值。

我們通過在第一個OPTIONAL MATCH之後添加一個WHERE來解決這個問題,只有當您在第二個OPTIONAL MATCH中查找的模式存在於最後一個節點之外時,強制匹配成功(即使這樣一個模式重用了OPTIONAL MATCH中的關係和節點)。

+0

謝謝,這個解決方案非常完美。 – Mehran

+0

很高興聽到它!當你有機會時,你能接受這個答案嗎? – InverseFalcon

+0

對不起,我以爲我做到了 – Mehran

1

您可以嘗試收集尾巴另外:

PROFILE 
MATCH (n1:S) 
OPTIONAL MATCH (n1)-[:R]->(n2:R)<-[:R]-(n3:E) 
WITH n1, [null] + ((n3)-[:R]->(:R:L)) as tail 
WITH n1, tail, size(tail) as tailSize 
UNWIND tail as t 
WITH n1, tailSize, t WHERE (tailSize = 2 AND NOT t is NULL) OR tailSize = 1 
WITH n1, nodes(t) as nds 
WITH n1, nds[0] as n3t, nds[1] as n4 
RETURN labels(n1), labels(n3t), labels(n4)