2016-11-14 92 views
0

我有一組節點,所有標記爲Word。我想用稱爲距離的關係將每個單詞連接到所有其他單詞。我做了以下查詢:Neo4j Cypher優化在笛卡爾積中的每個節點之間創建關係

 
match (word1:Word) 
with word1 
match (word2:Word) 
where word1 <> word2 
merge (word1)-[distance:DISTANCE ]->(word2) 
return word1, distance, word2 

它永遠運行。只有〜600個節點,雖然我期望600 * 600的關係,但查詢不應該運行兩個小時! Java比Neo4j更快。你有什麼建議讓它更快?我已經在其中一個屬性上添加了一個索引,但它並沒有改進。

+1

這是在一次交易中創建的幾乎360K的關係,根據您的記憶設置而定,這可能很多。 –

+1

請注意,您還將返回360K行。至少,你可以消除你的回報,因爲它似乎並不需要它。你也不需要在DISTANCE關係上添加一個變量,如果你不打算在查詢中做更多的事情。如果您需要批量合併,請嘗試APOC庫程序apoc.periodic.commit()。 – InverseFalcon

回答

3

一些觀察:

  1. 您的查詢將嘗試在一個事務中進行2 * 600 * 599(或718800)MERGE操作。因爲2的原因是因爲每一對單詞(比如x和y)都會被看到兩次(如x/y和y/x)。你(大概)只想執行一半的操作。
  2. x/y和y/x行爲也會導致嘗試確保每個字對有2個DISTANCE關係 - 任一方向都有一個。這可能是(假設)兩倍於你想要(或需要)的關係數量。
  3. 嘗試在單個事務中執行720K(甚至只是360K)操作可能會導致DB服務器內存不足。

這是修改後的查詢,可能會解決上述問題。 ID(w1) < ID(w2)測試確保一對中的2個字不相同,並且相同的對只處理一次。它還使用APOC程序apoc.periodic.iterate並行地在單獨的事務中一次創建10K關係。

CALL apoc.periodic.iterate(
    'MATCH (w1:Word), (w2:Word) WHERE ID(w1) < ID(w2) RETURN w1, w2', 
    'CREATE (w1)-[:DISTANCE]->(w2)', 
    {batchSize:10000, parallel:true}) YIELD batches, total 
RETURN * 

注1:此查詢假設你開始沒有在DB任何DISTANCE關係,所以它使用更便宜的CREATE條款,而不是MERGE。如果DISTANCE關係已經存在,則改爲使用MERGE(但如果第一個關係的方向相反,則可能會在同一對之間創建第二個關係)。

注意2:並行執行批次應該是安全的,因爲新的Cypher代碼無法解決問題#2。如果兩個事務試圖同時在相同的兩個節點之間創建相反方向的關係,則可能導致deadlock,這會導致至少一個事務失敗。

注意3:此查詢假定第一條語句(與MATCH子句)本身不會耗盡內存或花費太長時間來處理。如果這種假設是錯誤的,那麼使用apoc.periodic.commit的適當修改的查詢應該可行。

+0

感謝您的幫助,並指引我走向apoc。我嘗試了查詢。它在30分鐘內執行。但它確實很慢。 :( – bobby