開發與維運

將Neo4j數據導入到GDB

本文使用具體示例介紹導入Neo4j數據到GDB流程。
在進行操作前需要您已經準備好以下資源。

  1. Neo4j Server,保存有待導出數據,能正常提供讀寫服務。
  2. Cypher Shell,連接到Neo4j Server,控制檯命令交互,導出數據到文件。
  3. 阿里雲GDB,數據導入的目的端。
  4. 阿里雲OSS,用於臨時存放Neo4j導出的中間文件,提供給GDB導入使用。
  5. 中間文件格式轉換工具 graphml2csv.py,轉換graphML格式文件到GDB支持的CSV格式。
  6. 阿里雲GDB導入API小工具 GdbLoader.py,也可以直接使用curl命令交互。

1. 寫入測試數據到Neo4j

如果待導出的數據已經保存在Neo4j,可以跳過此步驟,本文演示可操作的完整流程。

Cypher-Shell執行以下語句,寫入測試數據(TinkerPop modern)。

# 寫入點數據
create (:person {id:"1", name:"marko", age:29});
create (:person {id:"2", name:"vadas", age:27});
create (:person {id:"3", name:"lop", lang:"java"});
create (:person {id:"4", name:"josh", age:32});
create (:person {id:"5", name:"ripple", lang:"java"});
create (:person {id:"6", name:"peter", age:35});

# 寫入邊數據
start n=node(*), m=node(*) where n.id="6" and m.id="3" create (n)-[:created {id:"12", weight:0.2}]->(m);
start n=node(*), m=node(*) where n.id="4" and m.id="3" create (n)-[:created {id:"11", weight:0.4}]->(m);
start n=node(*), m=node(*) where n.id="4" and m.id="5" create (n)-[:created {id:"10", weight:1.0}]->(m);
start n=node(*), m=node(*) where n.id="1" and m.id="3" create (n)-[:created {id:"9", weight:0.4}]->(m);
start n=node(*), m=node(*) where n.id="1" and m.id="4" create (n)-[:knowns {id:"8", weight:1.0}]->(m);
start n=node(*), m=node(*) where n.id="1" and m.id="2" create (n)-[:knowns {id:"7", weight:0.5}]->(m);

2. 導出Neo4j數據到文件

以下使用Neo4j apoc功能導出數據到文件,文件格式是graphml。注意導出命令的參數。


neo4j> call apoc.export.graphml.all("result.ml",{readlabels:true, useTypes:true});
+-----------------------------------------------------------------------------------------------------------------------------------------+
| file        | source                        | format    | nodes | relationships | properties | time | rows | batchSize | batches | done |
+-----------------------------------------------------------------------------------------------------------------------------------------+
| "result.ml" | "database: nodes(6), rels(6)" | "graphml" | 6     | 6             | 30         | 54   | 0    | -1        | 0       | TRUE |
+-----------------------------------------------------------------------------------------------------------------------------------------+

1 row available after 261 ms, consumed after another 12 ms

由於我們示例的測試數據比較小,以下給出導出文件的完整內容,方便核對。


<?xml version="1.0" encoding="UTF-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
<key id="name" for="node" attr.name="name" attr.type="string"/>
<key id="id" for="node" attr.name="id" attr.type="string"/>
<key id="lang" for="node" attr.name="lang" attr.type="string"/>
<key id="age" for="node" attr.name="age" attr.type="long"/>
<key id="weight" for="edge" attr.name="weight" attr.type="double"/>
<key id="id" for="edge" attr.name="id" attr.type="string"/>
<graph id="G" edgedefault="directed">
<node id="n0" labels=":person"><data key="labels">:person</data><data key="id">1</data><data key="name">marko</data><data key="age">29</data></node>
<node id="n1" labels=":person"><data key="labels">:person</data><data key="id">4</data><data key="name">josh</data><data key="age">32</data></node>
<node id="n2" labels=":person"><data key="labels">:person</data><data key="id">5</data><data key="name">ripple</data><data key="lang">java</data></node>
<node id="n3" labels=":person"><data key="labels">:person</data><data key="id">6</data><data key="name">peter</data><data key="age">35</data></node>
<node id="n20" labels=":person"><data key="labels">:person</data><data key="id">2</data><data key="name">vadas</data><data key="age">27</data></node>
<node id="n21" labels=":person"><data key="labels">:person</data><data key="id">3</data><data key="name">lop</data><data key="lang">java</data></node>
<edge id="e0" source="n3" target="n21" label="created"><data key="label">created</data><data key="id">12</data><data key="weight">0.2</data></edge>
<edge id="e20" source="n1" target="n21" label="created"><data key="label">created</data><data key="id">11</data><data key="weight">0.4</data></edge>
<edge id="e21" source="n1" target="n2" label="created"><data key="label">created</data><data key="id">10</data><data key="weight">1</data></edge>
<edge id="e22" source="n0" target="n21" label="created"><data key="label">created</data><data key="id">9</data><data key="weight">0.4</data></edge>
<edge id="e23" source="n0" target="n1" label="knowns"><data key="label">knowns</data><data key="id">8</data><data key="weight">1</data></edge>
<edge id="e40" source="n0" target="n20" label="knowns"><data key="label">knowns</data><data key="id">7</data><data key="weight">0.5</data></edge>
</graph>
</graphml>

3. 轉換導出文件格式

阿里雲GDB目前不支持導入graphml格式文件數據,可以使用下面工具轉換graphml格式到GDB支持的Gremlin(CSV)格式。

python graphml2csv.py -i result.ml
infile = result.ml
Processing result.ml
Wrote 6 nodes and 24 attributes to result-nodes.csv.
Wrote 6 edges and 18 attributes to result-edges.csv.

轉換成功後有以下點和邊數據文件,可以看到點邊都有一個id的屬性字段。

# CSV點數據文件
 $ cat result-nodes.csv
~id,~label,name:string,id:string,lang:string,age:long
0,person,marko,1,,29
1,person,josh,4,,32
2,person,ripple,5,java,
3,person,peter,6,,35
20,person,vadas,2,,27
21,person,lop,3,java,

# CSV邊數據文件
 $ cat result-edges.csv
~id,~from,~to,~label,weight:double,id:string
0,3,21,created,0.2,12
20,1,21,created,0.4,11
21,1,2,created,1,10
22,0,21,created,0.4,9
23,0,1,knowns,1,8
40,0,20,knowns,0.5,7

轉換常見問題

  1. GDB不支持多label。如果數據中包含多label的點,轉換腳本去掉前綴冒號(:),剩下字段當單label值輸出。例如兩個標籤workerdoctor的點,轉換後標籤是worker:doctor
  2. Neo4j默認隱藏點和邊的ID字段,內部使用數值表示。導出graphml格式數據中包含有內部ID字段。由於格式規範要求,點ID會添加字符'n',邊ID會添加字符'e',導出腳本轉換時去掉了前綴。
  3. graphml格式會在開頭定義數據schema,但可能不完整。轉換時出現KeyError(xxx)的錯誤可能就是數據內容不在schema定義的範圍內。可參照在文件開頭添加該字段的定義。注意點和邊是分開定義的。

4. 導入數據文件到GDB

上述轉換後得到點和邊兩個csv數據文件,我們使用GDB導入工具發送導入命令完成數據導入。當然您也可以參照阿里雲GDB導入文檔使用CURL操作導入。

上傳轉換後的點、邊CSV文件到OSS bucket。注意檢查bucket的地域和GDB實例是否相同,如果不一致,可以申請新的相同地域bucket。以下使用OSS命令行工具ossutil上傳數據到OSS,請替換您的bucket名稱。


#點文件
./ossutil cp result-nodes.csv oss://${mybucket}/neo4j-data/result-nodes.csv

#邊文件
./ossutil cp result-edges.csv oss://${mybucket}/neo4j-data/result-edges.csv

使用導入工具依次添加導入點任務和導入邊任務,注意等導入點完成後再添加導入邊任務,可以使用添加任務時返回的任務ID查詢任務詳情,檢查是否完成。

以下命令需要使用到您的GDB實例參數,可以參照導入文檔查找參數值


# 添加導入點任務
python GdbLoader.py --host ${mygdb-endpoint}:8182 --username ${username} --password ${password} --todo add_task --source oss://{mybucket}/neo4j-data/result-nodes.csv --arn acs:ram::${my-uid}:role/${role-name}

# 添加導入邊任務
python GdbLoader.py --host ${mygdb-endpoint}:8182 --username ${username} --password ${password} --todo add_task --source oss://${mybucket}/neo4j-data/result-edges.csv --arn acs:ram::${my-uid}:role/${role-name}

# 查詢任務詳情
python GdbLoader.py --host ${mygdb-endpoint}:8182 --username ${username} --password ${password} --todo get_task --loaderId 552617AF-4F1E-4CD8-9533-A2EC154688DC

5. 驗證導入數據

導入完成後,我們就能使用各種SDK接入GDB訪問數據,簡單起見,下面使用CURL讀取一個邊數據驗證。其他語言的接入驗證可以參照GDB各環境的接入文檔。

curl -u ${username}:${password} -X POST -d '{"gremlin":"g.E(\"21\").valueMap(true)"}' ${mygdb-endpoint}:8182 | python -m json.tool

Leave a Reply

Your email address will not be published. Required fields are marked *