2016-11-16 61 views
2

我有一個大圖模型,需要將以下查詢的結果寫入csv。從Neo4j載入9M行並將其寫入CSV會拋出內存異常

Match (u:USER)-[r:PURCHASED]->(o:ORDER)-[h:HAS]->(i:ITEM) return u.id as userId,i.product_number as itemId 

當我「解釋」的查詢,這是結果我得到: enter image description here

這表明,估算結果是9M左右的東西。我的問題是:

1)需要很長時間才能得到回覆。從neo4j-shell需要38分鐘!這是正常的嗎?順便說一句,我有所有架構索引那裏,他們都在線。

2)當我使用SpringDataNeo4j來獲取結果時,它會拋出一個「java.lang.OutOfMemoryError:GC開銷超限」的錯誤,當SDN嘗試將加載的數據轉換爲我們的@QueryResult對象時會發生這種情況。

我試圖以各種不同的方式優化查詢,但沒有任何改變!我的印象是我做錯了什麼。有誰知道我如何解決這個問題?我應該去批量讀/寫嗎?

P.S我使用的Neo4j comunity版版本:3.0.1,這些都是我的sysinfos: enter image description here

,這些都是我的服務器CONFIGS。

dbms.jvm.additional=-Dunsupported.dbms.udc.source=tarball 
use_memory_mapped_buffers=true 
neostore.nodestore.db.mapped_memory=3G 
neostore.relationshipstore.db.mapped_memory=4G 
neostore.propertystore.db.mapped_memory=3G 
neostore.propertystore.db.strings.mapped_memory=1000M 
neostore.propertystore.db.index.keys.mapped_memory=500M 
neostore.propertystore.db.index.mapped_memory=500M 

回答

2

感謝Vince和Michael的評論我找到了解決方案! 做了一些實驗後,發現服務器的響應時間確實很好! 1.5億分鐘的900萬數據!問題與SDN一樣,Vince提到!當SDN嘗試將數據轉換爲@QueryResult對象時,會發生OOM。爲我們的應用程序增加堆內存不是一個永久的解決方案,因爲我們將來會有更多的行!因此,我們決定使用neo4j-jdbc-driver進行大數據查詢... &它的工作原理類似於噴氣式飛機!下面是我們使用的代碼示例:

Class.forName("org.neo4j.jdbc.Driver"); 
    try (Connection con = DriverManager.getConnection("jdbc:neo4j:bolt://HOST:PORT", "USER", "PASSWORD")) { 

     // Querying 
     String query = "match (u:USER)-[r:PURCHASED]->(o:ORDER)-[h:HAS]->(i:ITEM) return u.id as userId,i.product_number as itemId"; 
     con.setAutoCommit(false); // important for large dataset 
     Statement st = con.createStatement(); 
     st.setFetchSize(50);// important for large dataset 

      try (ResultSet rs = st.executeQuery(query)) { 
       while (rs.next()) { 
        writer.write(rs.getInt("userId") + ","+rs.getInt("itemId")); 
        writer.newLine(); 
       } 

      } 

     st.setFetchSize(0); 
     writer.close(); 
     st.close(); 

    } 

只要確保你使用「con.setAutoCommit(假)」和「st.setFetchSize(50)」如果你知道你要加載大量數據集。感謝大家 !

6

雖然它匹配他們,當你使用SDN它必須收集輸出到單個@QueryResult對象的Neo4j會流導致你。爲了避免OOM問題,您需要確保您的應用程序有足夠的堆內存可用來加載所有9m響應,或者使用neo4j-shell,或者使用專門構建的流接口(例如https://www.npmjs.com/package/cypher-stream)。 (買者自負:我沒有嘗試這樣做,但它看起來像它應該做的伎倆)

+0

謝謝Vince,你給了我一個關於@QueryResult的好消息! – Lina

3

你的配置設置不正確的Neo4j的3.0.1

你必須設置在conf下堆/neo4j-wrapper.conf,例如8G

和conf/neo4j.conf中的頁面緩存(查看你的商店,你只需要2G的頁面緩存)。

也正如你所看到的,它將創造超過800萬行。

你可能有更多的運氣與此查詢:

Match (u:USER)-[:PURCHASED]->(:ORDER)-[:HAS]->(i:ITEM) 
with distinct u,i 
return u.id as userId,i.product_number as itemId 

它也沒有意義返回8M行neoj殼是誠實的。在中間 如果要衡量它,更換RETURNWITH並添加RETURN count(*)

Match (u:USER)-[r:PURCHASED]->(o:ORDER)-[h:HAS]->(i:ITEM) 
with distinct u,i 
WITH u.id as userId,i.product_number as itemId 
RETURN count(*) 

另一種優化可能是通過項目和用戶去,做一個散列連接的全局查詢這樣的:

Match (u:USER)-[:PURCHASED]->(o:ORDER)-[:HAS]->(i:ITEM) 
USING JOIN ON o 
with distinct u,i 
WITH u.id as userId,i.product_number as itemId 
RETURN count(*) 

那我可能會做,以減少返回的結果數量的另一件事是嘗試聚集。

Match (u:USER)-[:PURCHASED]->(o:ORDER)-[:HAS]->(i:ITEM) 
with distinct u,i 
WITH u, collect(distinct i) as products 
WITH u.id as userId,[i in products | i.product_number] as items 
RETURN count(*) 
+0

謝謝邁克爾, 你是對的,dbms.memory.pagecache.size被設置在一個錯誤的文件。我改變了它。關於返回結果的數量,我不想減少它們,我需要它們。我需要創建一個csv的userId,itemId ...不能使用任何分組...我嘗試了所有你提出的查詢(vi neo4j-shell ...)都有相同的響應時間。我認爲我的數據沒有真正標準化:-)但是我需要所有的重複。 – Lina