2017-03-16 341 views
1

一個小背景:我正在嘗試使用Neo4J(作爲一個新手,但是在其他數據庫技術方面經驗豐富),以便在我們的身份識別業務中用作主數據管理系統智能,特別是在建立一個地方圖形,身份屬性(例如:電子郵件地址,電話號碼,選民名單數據等),以及這些節點之間的關係來表達一些有意義的信息,例如在使用電子郵件地址的情況下,或者電話號碼被註冊的地方。Neo4J Cypher:匹配多個屬性並創建關係的性能

系統需要的屬性:我想這個系統有那些valuble給我們一些具體的性能:

  • 的從顯著數量的供應商(100+)信息快速攝取,這就排除了冗長(小時)ETL過程,簡短的都可以!
  • 在線任何時候,這排除了批量導入器的使用,我們最有可能使用容錯羣集,分片將是好的:)
  • 容量最終攝取〜30G記錄/年(〜1000 /第二),並保留它們,創建和保留〜100G關係/年,現在我們正在攝取〜這個負載的1/10。

我被困在哪裏:我一直在試驗Azure中的單個節點,32GB RAM,4個內核,非本地磁盤,運行Debian 8和Neo4J 3.1.1。通過使用LOAD CSV或自制Java和螺栓,在幾十分鐘內,這愉快地攝取和聯繫英國郵政地址文件(PAF),大約29M記錄。我還攝入了一組電子郵件地址數據的測試集,但大約有20百萬條記錄,但現在需要根據兩個數據集之間匹配的郵政編碼,建築物編號以及可能的其他字段建立關係。這就是事情用暗號時得到更慢,這裏的最快的查詢我已經能夠迄今爲止創造:

UNWIND {list} AS i 
MATCH(e:DDSEMAIL) WHERE ID(e) = i WITH e 
MATCH(s:SUBBNAME) USING INDEX s:SUBBNAME(SBNA) 
    WHERE upper(e.Building) = s.SBNA WITH e,s 
MATCH(m:MAINFILE) 
    WHERE trim(split(e.Postcode,' ')[0]) = m.OUTC AND 
    trim(split(e.Postcode,' ')[1]) = m.INCO AND 
    right('0000'+e.HouseNo,4) = m.BNUM AND 
    (m)-[:IS_SUBBNAME]->(s) 
CREATE (e)-[r:USED_AT]->(m) 
RETURN COUNT(r); 

指標爲:

ON :DDSEMAIL(HouseNo) ONLINE 
ON :DDSEMAIL(Postcode) ONLINE 
ON :DDSEMAIL(Building) ONLINE 
ON :MAINFILE(OUTC)  ONLINE 
ON :MAINFILE(INCO)  ONLINE 
ON :MAINFILE(BNUM)  ONLINE 
ON :SUBBNAME(SBNA)  ONLINE 

請注意{列表}參數通過已經枚舉了所有〜20M DDSEMAIL節點的Java客戶端通過螺栓提供,並且正在批量處理(通常爲一次1000個ID)。

每個ID需要100-200msecs,經過157000個ID的測試運行需要7.3小時,表明完全執行時間約爲760小時或大於1個月。底層機器出現CPU綁定(沒有顯着的IO等待時間)。

縱觀解釋這個查詢,有沒有完整的掃描,這是所有模式折射率匹配(一旦我列入明確的指標語句),所以我不知道到哪裏尋找更多的速度..

(編輯以添加此PROFILE輸出):

PROFILE part 1 PROFILE part 2

這表明匹配到郵政編碼的兩個部分是過濾很多行(56K)時,它可能是更好的重新請訂購這些字段以減少過濾器輸入大小。 (作爲編輯結束)

作爲(非常不公平的)比較,我將兩組數據從CSV文件推送到用C#/。NET編寫的自定義Bloom過濾器,它執行與上面相似的字段重新格式化,然後連接以生成文本鍵,並將這些鍵匹配在一起。這完成了我的筆記本電腦的單個核心在5分鐘內完成所有20M電子郵件記錄與29M PAF記錄的卷積。這主要是IO界限。

現在我正在考慮使用外部應用程序或用戶過程來執行記錄匹配,並且只是使用Cypher創建關係,但是它會錯誤地避免一個寫得很好的查詢引擎,它應該能夠執行此操作比現在快得多。

請問我該如何改善性能?

+0

可以將查詢(在較小的數據集上)的PROFILE或EXPLAIN的屏幕截圖添加到您的描述中(展開所有計劃節點之後),這可能有助於查看可以改進的地方。 – InverseFalcon

回答

0

如果我沒有記錯,當比較值(如UPPER()或LOWER()或TRIM())發生轉換時,如果源自另一個節點屬性,則索引將無法正確使用。您可能需要先執行這些操作並將它們別名,然後進行匹配。

提供索引提示解決了這個問題,我認爲,所以你與s.SBNA的匹配應該正確使用索引,但是如果在m:MAINFILE上有任何匹配屬性的索引,那可能不會使用該指數。看到

測試此有差別,這個查詢與上一個較小的數據集上了年紀的查詢:

UNWIND {list} AS i 
MATCH(e:DDSEMAIL) WHERE ID(e) = i 
WITH e, upper(e.Building) as SBNA 
MATCH(s:SUBBNAME) 
WHERE s.SBNA = SBNA 
WITH e,s, trim(split(e.Postcode,' ')[0]) as OUTC, 
      trim(split(e.Postcode,' ')[1]) as INCO, 
      right('0000'+e.HouseNo,4) as BNUM 
MATCH(m:MAINFILE) 
WHERE OUTC = m.OUTC AND 
     INCO = m.INCO AND 
     BNUM = m.BNUM AND 
     (m)-[:IS_SUBBNAME]->(s) 
CREATE (e)-[r:USED_AT]->(m) 
RETURN COUNT(r); 

另外,如果你可以添加一個配置文件的截圖或查詢的EXPLAIN你的描述(展開所有計劃節點之後),這可能有助於查看事情可能改進的地方。

編輯

正如你在你的描述中提到的,這些配料可以是一個好主意。 APOC程序有apoc.periodic.iterate(),這可能對此有所幫助。

讓我們看看我們是否可以將它應用於您的查詢。嘗試了這一點:

WITH {list} AS list 
CALL apoc.periodic.iterate(' 
UNWIND {list} as list 
RETURN list 
', ' 
WITH {list} as i 
MATCH(e:DDSEMAIL) WHERE ID(e) = i 
WITH e, upper(e.Building) as SBNA 
MATCH(s:SUBBNAME) 
WHERE s.SBNA = SBNA 
WITH e,s, trim(split(e.Postcode,' ')[0]) as OUTC, 
      trim(split(e.Postcode,' ')[1]) as INCO, 
      right('0000'+e.HouseNo,4) as BNUM 
MATCH(m:MAINFILE) 
WHERE OUTC = m.OUTC AND 
     INCO = m.INCO AND 
     BNUM = m.BNUM AND 
     (m)-[:IS_SUBBNAME]->(s) 
MERGE (e)-[:USED_AT]->(m) 
', {batchSize:1000, iterateList:true, params:{list:list}}) YIELD batches, total, committedOperations, failedOperations, failedBatches, errorMessages 
RETURN batches, total, committedOperations, failedOperations, failedBatches, errorMessages 

我們不得不犧牲然而回國創建關係的總數,因爲我們不能從成批的查詢返回值。

+0

好的,謝謝@InverseFalcon,我已經試過了這個,一次執行就會使db命中次數減少一半,然後再進行更長時間的測試...... – Phlash

+0

好吧,看起來不錯,每個ID都需要~30msecs來處理在第一次達到900次之後,它會以大約1.3秒/內存的速度咀嚼磁盤數小時。我將在週末結束運行,但這看起來像是我可能面臨的大部分時間內的低溫高速緩存問題...... – Phlash

+0

嚴重奇怪,我斷開了Web客戶端並註銷了測試機器(離開測試在屏幕會話中運行),一切似乎運行得更快......週一更多數據! – Phlash