相比圖形數據的查詢,Neo4j更新圖形數據的速度較慢,通常情況下,Neo4j更新數據的工作流程是:每次數據更新都會執行一次資料庫連接,打開一個事務,在事務中更新數據。當數據量非常大時,這種做法非常耗時,大多數時間耗費在連接資料庫和打開事務上,高效的做法是利用Neo4j提供的參數(Parameter) ...
相比圖形數據的查詢,Neo4j更新圖形數據的速度較慢,通常情況下,Neo4j更新數據的工作流程是:每次數據更新都會執行一次資料庫連接,打開一個事務,在事務中更新數據。當數據量非常大時,這種做法非常耗時,大多數時間耗費在連接資料庫和打開事務上,高效的做法是利用Neo4j提供的參數(Parameter)機制和UNWIND子句:在一次數據更新中,進行一次連接,打開一次事務,批量更新數據;參數用於提供列表格式的數據,UNWIND子句是把列表數據展開成一行一行的數據,每行數據都會執行結構相同的Cypher語句。再批量更新圖形數據之前,用戶必須構造結構固定的、參數化的Cypher語句。當Cypher語句的結構相同時,Neo4j資料庫直接從緩存中復用已生成的執行計劃,而不需要重新生成,這也能夠提高查詢性能。
除了官方的Neo4j Driver之外,本文分享使用Neo4jClient對圖形數據批量更新,Neo4jClient提供的功能更強大,並支持參數和批量更新操作。
我的Neo4j系列的文章收錄在:Neo4j
一,參數和UNWIND子句
1,通過RESTful API傳遞參數
Neo4j提供HTTP API處理Cypher語句和參數,在示例代碼中,Neo4j的參數通過HTTP請求傳遞,statement定義的是查詢語句,parameters定義的是參數。
在批量更新數據時,沒有必要發送多個HTTP請求,通過參數,可以在一個HTTP請求(Request)中,開始一個事務,在事務中執行Cypher語句批量更新數據,最後提交該事務。
在發送HTTP請求傳遞參數批量更新數據時,設置HTTP Request的參數如下:
POST http://localhost:7474/db/data/transaction/commit Accept: application/json; charset=UTF-8 Content-Type: application/json
註意:在HTTP API中,引用參數的格式是:{param}。
{ "statements" : [ { "statement" : "CREATE (n {props}) RETURN n", "parameters" : { "props" : { "name" : "My Node" } } } ] }
2,展開(UNWIND)子句
UNWIND子句把列表式的數據展開成一行一行的數據,每一個行都包含更新所需要的全部信息,列表式的數據,可以通過參數來傳遞。
例如,定義參數events,該參數是一個JSON字元串,鍵events是參數名,其值是一個數組,包含兩個數組元素。
{ "events" : [ { "year" : 2014, "id" : 1}, {"year" : 2014, "id" : 2 } ] }
通過$events引用參數,UNWIND子句把events數組中的兩個元素展開,每個元素執行一次Cypher語句,由於Cypher的語句結構固定,因此,執行計劃被緩存起來,在執行數據更新任務時,參數被UNWIND子句展開,復用執行計劃,提高數據更新的速度。
UNWIND $events AS event MERGE (y:Year { year: event.year }) MERGE (y)<-[:IN]-(e:Event { id: event.id }) RETURN e.id AS x ORDER BY x
二,在Neo4j Browser中使用參數
Neo4j Browser是Neo4j內置的瀏覽器,用於管理資料庫,更新資料庫和查詢數據,再命令窗體中,通過“:”能夠引用內置的命令,例如,通過 ":param"能夠定義參數,並能夠在下一個Cypher語句中引用參數。
1,通過:param命令定義參數
在Neo4j Browser中,輸入第一個命令,通過:param 命令定義參數,
2,通過$param引用參數
緊接著,輸入Cypher語句,通過$param引用參數
3,查看創建的圖形
參數是一個列表格式的數據,在參數events中,兩個event的year屬性都是2014,因此,MERGE子句只會創建一個Year節點;由於兩個event的id屬性不同,因此MERGE子句會創建兩個Event節點,並創建Year節點和Event節點之間的關係,圖形如下圖:
三,使用Neo4jClient批量更新數據
在工程(Projects)中輸入命令安裝Neo4jClient,
Package-Install Neo4jClient
1,連接Neo4j資料庫
創建客戶端,連接到資料庫,創建的Uri的格式是:http://host_name:7474/db/data,並輸入用戶名和密碼,然後創建圖形客戶端,並連接到Neo4j資料庫。
private GraphClient _client; public Neo4jClientProvider() { _client = new GraphClient(new Uri("http://localhost:7474/db/data"), "user_name", "password"); _client.Connect(); }
2,批量創建節點
傳遞List<T>參數,通過Unwind函數引用List,併為參數命名為"ns",在Cypher語句中引用參數"ns"
public void CreateNodes(List<DataModel> nodes) { _client.Cypher .Unwind(nodes, "ns") .Create("(n:NodeLable)") .Set("n.NodeID=ns.NodeID") .Set("n.Name=ns.Name") .ExecuteWithoutResults(); }
2,批量創建關係
在List<T>參數中,傳遞兩個節點的映射,在Neo4j資料庫中,關係必須具有類型,因此,在把參數傳遞到Neo4j數據中時,需要確定兩個節點和關係類型,以創建關係
public bool CreateRelationships(List<RelationshipModel> nodes) { _client.Cypher .Unwind(nodes, "ns") .Match("(n:Lable1),(s:Lable2)") .Where("n.NodeID=ns.NodeID and s.NodeID=ns.RelatedID") .Merge("(n)-[r:RelationshipType]->(s)") .ExecuteWithoutResults(); }
參考文檔:
Getting Started with Neo4j in .NET with Neo4jClient Library
Batch insert nodes and relations neo4jclient
5 Tips & Tricks for Fast Batched Updates of Graph Structures with Neo4j and Cypher
關於Neo4j和Cypher批量更新和批量插入優化的5個建議