1. 程式人生 > 其它 >Neo4j 第五篇:批量更新資料

Neo4j 第五篇:批量更新資料

相比圖形資料的查詢,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();
}

參考文件:

3.3.6. UNWIND

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個建議