2017-07-03 104 views
2

沒有得到不必要的太具體,我在Neo4j 3.2中遇到以下Cyper問題。假設我們有一個包含3個實體的數據庫:User,Comment,Like。Neo4j 3.2 Cypher低性能

無論出於何種原因,我試圖運行下面的查詢:

MATCH (n:USER) WHERE n.name = "name" 
WITH n 
MATCH (o:USER) 
WITH n, o, "2000" as number 
MATCH (n)<-[:CREATED_BY]-(:COMMENT)-[:HAS]->(l:LIKE)-[:CREATED_BY]->(o) 
RETURN n, o, number, count(l) 

查詢只需幾分鐘即可完成。但是,如果我只是刪除「2000」作爲部分,它會在幾十毫秒內完成。

有沒有人有解釋爲什麼?

編輯: 頂部圖像,與「2000」作爲號碼部分;底部,沒有它。

+1

我的假設是你/ cypher創建32969個新的字符串。你是否在JVM中執行gc暫停?使用數字2000時您是否遇到同樣的情況? – manonthemat

回答

4

你將不得不清理你的查詢,現在你不使用索引(所以用特定名稱初始匹配是慢),然後執行笛卡爾針對所有產品:用戶節點,然後爲每一行創建字符串。因此,首先在USER(name)上創建一個索引,以便快速找到您的開始節點。我們將不得不清理比賽的其餘部分。

嘗試這樣代替:

MATCH (n:USER) WHERE n.name = "name" 
WITH n, "2000" as number 
MATCH (n)<-[:CREATED_BY]-(:COMMENT)-[:HAS]->(l:LIKE)-[:CREATED_BY]->(o:User) 
RETURN n, o, number, count(l) 

你應該在查詢看到一個類似的計劃與此查詢爲沒有「2000」。

這樣做的原因是,雖然你的計劃與您匹配o笛卡爾積,規劃是足夠的智能,實現有一個附加的限制爲o,它曾在圖案出現在你的最後一場比賽,並且針對這種情況進行優化可以避免執行笛卡爾產品。

然而,一個新變量number的介紹阻止了規劃人員認識到這基本上是相同的情況,因此規劃人員沒有優化笛卡爾產品。

現在,嘗試明確您希望執行查詢的方式,並儘量避免在查詢中使用笛卡爾積。

在這種特殊情況下,意識到當你在第三行有MATCH (o:User)時,這並不是說o的類型是a:用戶在後面的匹配中,而是說你的結果中的每一行到目前爲止,針對所有用戶節點執行笛卡爾乘積,然後針對每個用戶節點,查看提供的模式中存在哪些節點。與簡單地擴展提供的模式並獲取任何內容相比,這是很多不必要的工作:您在模式的另一端找到的用戶節點。

編輯

至於獲得兩項:LIKE和:厭惡節點數,也許嘗試這樣的事:

MATCH (n:USER) WHERE n.name = "name" 
WITH n, "2000" as number 
MATCH (n)<-[:CREATED_BY]-(:COMMENT)-[:HAS]->(likeDislike)-[:CREATED_BY]->(o:User) 
WITH n, o, number, head(labels(likeDislike)) as type, count(likeDislike) as cnt 
WITH n, o, number, CASE WHEN type = "LIKE" THEN cnt END as likeCount, CASE WHEN type = "DISLIKE" THEN cnt END as dislikeCount 
RETURN n, o, number, sum(likeCount) as likeCount, sum(dislikeCount) as dislikeCount 

假設你仍然需要number變量在那裏。

+0

感謝您的回答。這確實清除了一些事情。然而,像這樣寫查詢的原因是,第3行不僅僅是簡單地匹配所有其他用戶。爲了這個例子,假設數據庫中還有DISLIKE節點,儘管這將是一個設計流程。查詢應該計算n與其他o之間的DISLIKE節點的數量,然後也計算n和其他o之間的所有LIKE節點的數量。 – user3455402

+2

在這裏執行笛卡爾產品仍然不是一個好的理由,如果您必須檢查兩種類型的節點,問題只會變得更糟。沒有理由檢查每個單獨的模式:USER。而只是檢查模式本身找到哪些用戶。對於您的DISLIKE用例,可能不容易標記潛力:LIKE或DISLIKE節點,然後使用CASE爲每個節點計數。 – InverseFalcon