GraphDBを学ぶ(3)neo4j:ノードとエッジの作成


TL;DR

  • neo4jを使ってGraphDBの扱い方を学びます
    • その第1段として,手作業でデータを登録し,検索する方法を紹介します
  • RDBMSベンチマークTPC-Hのテーブルを参考に,neo4jにノードを登録してみます(nation, regionのみ)

作業方針

  • データベースベンチマークTPC-HをMySQLで実行する(TPC-H v2.18.0)を参考に, sf=0.01 のサイズでデータベースを作成してデータの確認に使用します
    • sf=1でやったらデータの登録が終わらなるかもしれいないので,この記事では小さい(sf=0.01)データを扱います
  • TPC-Hのテーブルを見ながら,neo4jにデータを(最初は手作業で)投入,検索をしてみます
  • CUIのneo4jクライアントneo4j-clientを使用します

シンプルなデータ登録(Nation, Regionテーブルを参考に)

  • まず,投入するデータについて考えます
    • TPC-Hのテーブル群の中で,Nationテーブル(25エントリ),Regionテーブル(5エントリ)は,has-manyの関係にあり,scale factorにかかわらず各テーブルのエントリ数が固定です.
      • 使いやすそうな関係なので,neo4j(Cypher)のテストに使います
    • regionテーブルのエントリをグラフのノードへ登録する際には,Webクライアントで実験します
    • nationテーブルは,neo4j-clientを使います

regionノードの登録

MariaDB [sf1]> select * from region;
+-------------+-------------+---------------------------------------------------------------------------------------------------------------------+
| R_REGIONKEY | R_NAME      | R_COMMENT                                                                                                           |
+-------------+-------------+---------------------------------------------------------------------------------------------------------------------+
|           0 | AFRICA      | lar deposits. blithely final packages cajole. regular waters are final requests. regular accounts are according to  |
.....<snip>.....
|           4 | MIDDLE EAST | uickly special accounts cajole carefully blithely close requests. carefully final asymptotes haggle furiousl        |
+-------------+-------------+---------------------------------------------------------------------------------------------------------------------+
5 rows in set (0.00 sec)
  • 5つのRegion(地域)が登録されています
  • Regionテーブルは,R_NAME (fixed text, size 25)およびR_COMMENT (variable text, size 152)という,2つの属性を持つエントリからなります
  • そこで,neo4jに,各エントリをノードとして登録してみます

Cypherクエリでノードを1つ登録

  • R_NAMEが"AFRICA"のregionノードを登録してみます
CREATE
(:region{R_REGIONKEY:0, R_NAME:"AFRICA",R_COMMENT:"lar deposits. blithely final packages cajole. regular waters are final requests. regular accounts are according to"});
  • WebUIのコンソールに入力する場合は,以下のようにコマンドを記述してエンターキーか,再生ボタンを押します

  • (おまけ)ノードを削除したい場合は,該当するノードをMATCH句で取り出してDELETEします
MATCH (r :region{R_REGIONKEY:0}) DELETE r;
  • 以下のようなログ出力が行われ,ノードの登録ができたログが出力されます
Added 1 label, created 1 node, set 2 properties, completed after 12 ms.

Cypherクエリで複数ノードをまとめて登録

  • create句に加えて,ノードの情報を列挙すると,複数のノードをまとめて登録することができます.この操作で,残りのノードを登録します.
create
(:region{R_REGIONKEY:1, R_NAME:"AMERICA",R_COMMENT:"hs use ironic, even requests. s"}),
(:region{R_REGIONKEY:2, R_NAME:"ASIA",R_COMMENT:"ges. thinly even pinto beans ca"}),
(:region{R_REGIONKEY:3, R_NAME:"EUROPE",R_COMMENT:"ly final courts cajole furiously final excuse"}),
(:region{R_REGIONKEY:4, R_NAME:"MIDDLE EAST",R_COMMENT:"uickly special accounts cajole carefully blithely close requests. carefully final asymptotes haggle furiousl"});
  • WebUIでは以下のように入力されることになります

登録ノードの確認

  • match句ですべてのノード(条件無しでマッチ)を返す(表示する)クエリを発行します
match(n) return n
  • WebUIの場合,以下のようなグラーフとして表示されます
    • マウスでノードをドラッグできるので楽しいです
    • neo4j-clientでは行が表示されます

nationノードの登録

  • 前項のregionと同様の方法で,nationもノード登録します
  • しかし,プロンプトで登録していくのは面倒なので,csvファイルから取り込みます

MySQLからテーブルをcsv出力する

  • 1ノードずつ登録するのは面倒なので,まとめて登録する方法を考えます
  • mysqlのコマンドで,nationテーブルをcsvに出力します(参考:MySQLのSELECT文でcsvを出力する)
select N_NATIONKEY, N_NAME, N_COMMENT from nation
    into outfile '/tmp/nation.csv'
    fields terminated by ','
    optionally enclosed by '"';
  • /tmp/nation.csvに,以下のような国名とコメントのリストが得られます
cat /tmp/nation.csv

"ALGERIA"," haggle. carefully final deposits detect slyly agai"
.....<snip>.....
"UNITED STATES","y final packages. slow foxes cajole quickly. quickly silent platelets breach ironic accounts. unusual pinto be"

csvファイルのノードをまとめてneo4jに登録する

  • インポートしたいファイルをインポート用ディレクトリ(デフォルトでは/var/lib/neo4j/import)に置いて,load csvコマンドで,取り込むことができます.
    • csvファイルを1行ずつ読み込み,カンマでsplitして配列(line)に分解します
    • 配列の対応する要素(line[0]など)を,ノードの属性に設定して CREATE します
neo4j-client -u neo4j localhost

neo4j>
LOAD CSV FROM 'file:///nation.csv' AS line
CREATE (:nation {N_NATIONKEY: toInteger(line[0]), N_NAME: line[1], N_COMMENT: line[2]});

Created 25 nodes, set 75 properties, added 25 labels
0 rows returned in 106ms (rendered after 126ms)
  • 25個のノードが作られた旨のメッセージが出れば成功です
  • WebUIで確認すると,regionとnationの2種類のラベルでノードが合計30個できていることを確認できます

ノード間の関係の登録

  • regionとnationの関係(nationはregionにある)を登録します

Cypherクエリで関係を登録する

  • nationの各ノードは,いずれかのregionが設定されます
    • RDBMSの文脈では,nationテーブルのN_REGIONKEYに対応するR_REGIONKEYの値を持つregionのエントリがあります
    • その国(nation)はあの地域(region)に「ある」という関係をATという名前で示すことにします
  • ノード間の関係は,以下のようなCypherクエリで設定できます
    • 以下の例では,N_NATIONKEY=0のnationノード(アルジェリア)がR_REGIONKEY=0のregionノード(アフリカ)にある,という関係を設定しています
neo4j>
MATCH(n:nation{N_NATIONKEY: 0}), (r:region{R_REGIONKEY: 0})
CREATE (n)-[:AT]->(r);
  • WebUIから,関係の接続関係を見ることができます

  • (おまけ)関係の削除は,以下のように,特定の関係に名前(b)を付けて,DELETEを実行します
neo4j>
MATCH (n:nation{N_NATIONKEY: 0}) -[b:AT]-> 
(r:region{R_REGIONKEY: 0}) DELETE b;

関係をnationのcsvファイルから設定する

  • コマンド入力は面倒なので,各nation.csvの外部キー情報を使って,どのregionに属しているかの関係を設定します
neo4j>
LOAD CSV FROM 'file:///nation.csv' AS line
  MATCH (n:nation{N_NATIONKEY: toInteger(line[0])})
  MATCH (r:region{R_REGIONKEY: toInteger(line[2])})
CREATE (n)-[:AT]->(r);

Created 25 relationships);
0 rows returned in 83ms (rendered after 89ms)
  • WebUIから,国と地域がそれぞれノードとして存在し,国が地域に所属している関係をみることができます

参考