「Pythonでグラフデータベース Neo4j入門 for ビギナー」とか銘打っておきながら私自身もビギナーなので、すみません。
PythonでNeo4jを操作する環境構築と、データをいじってみるサンプルをご紹介します。
#1. Neo4jの導入#
まず、Mac OSXにNeo4Jを導入する方法から始めます。私の環境がYosemite 10.10.2なのでもし環境違いで何かエラー等あればコメント等で教えていただけると嬉しいです。
まず、JDKが必要ですが、Macに最初から入っているJavaではうまく動かないそうなので Oracle JDK 7を http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html から導入します。
次に、
http://neo4j.com/download/
にアクセスして、Neo4jのCommunity Edition(無料版)をダウンロードしてください。
neo4j-community-2.2.0-unix-2.tarがダウンロードされるので解凍してフォルダに入ります。
tar zvf neo4j-community-2.2.0-unix-2.tar
cd neo4j-community-2.2.0
そして起動します。
./bin/neo4j start
インストールは非常に簡単ですね!
ブラウザからアクセスできるユーザーインターフェースがあるので、それを使ってみていきます。
アクセス先は、
http://localhost:7474/browser/
です。
最初の起動時にIDとPasswordを設定することを求められるので、適宜設定します。
#2. PythonでNeo4jに接続する#
いくつかNeo4jに接続できるPythonライブラリがあるようですが、ここではNeo4jRestClientをつかってPythonからNeo4jに接続することにします。
pip install neo4jrestclient
pipって素晴らしいですね、インストールが本当に簡単!
neo4jRestClientのチュートリアルに従って試していきます。
from neo4jrestclient.client import GraphDatabase
url = "http://<ユーザーID>:<パスワード>@localhost:7474/db/data/"
gdb = GraphDatabase(url)
<ユーザーID>と<パスワード>の部分には、先ほど設定したものを書いてください。
これでPythonからNeo4jに接続されます。
次にNodeを2つ足してみます。aliceとbobの同い年の2人です。
alice = gdb.nodes.create(name="Alice", age=30)
bob = gdb.nodes.create(name="Bob", age=30)
実はbobはaliceの事を1980年から知っていたのだけど、aliceがbobを知ったのは3年後だった・・・
というノードを追加すると下記になります。
bob.relationships.create("Knows", alice, since=1980)
alice.relationships.create("Knows", bob, since=1983)
ではこれを表示させて見ましょう。(iPython notebookでpython動かしている事を前提として進めます)
ノードとノードの関係を含めて全部表示させるクエリを叩きます。また、data_contents=Trueを設定することがキモで、これをつけないとうまく動きません。(これがわからずにちょっと時間を食いました・・・)
gdb.query("MATCH (n)-[r]-(m) RETURN n, r, m", data_contents=True)
これをブラウザ上で見てみるには、 http://localhost:7474/browser/ にアクセスして
MATCH (n)-[r]-(m) RETURN n, r, m
#2. データをいじってみる#
先ほどまでのデータを一度削除します。
# All Delete
gdb.query("MATCH (n) OPTIONAL MATCH (n)-[r]-() DELETE n,r", data_contents=True)
その上で、3つのNode, Relationshipを追加します。
# Person Nodeの追加
alice = gdb.nodes.create(name="Alice", age=30)
bob = gdb.nodes.create(name="Bob", age=30)
ken = gdb.nodes.create(name="Ken", age=35)
alice.labels.add("Person")
bob.labels.add("Person")
ken.labels.add("Person")
# Relationshipの設定
bob.relationships.create("Knows", alice, since=1980)
alice.relationships.create("Knows", bob, since=1983)
alice.relationships.create("Knows", ken, since=2015)
Nodeというのはここでいうそれぞれの人のことを指し、RelationshipはAliceはBobを知っているといった関係性のことを指します。
iPython上で表示のクエリを叩くと、
gdb.query("MATCH (n)-[r]-(m) RETURN n, r, m", data_contents=True)
同じようなグラフが表示されます :D
次に書くPersonがBlogを持っていて、そのBlogとの関係性をブログの所持者:"Owner",購読者: "Subscribe"として定義してグラフを見てみます。
# Blog Nodeの追加
cam_blog = gdb.nodes.create(name="Camera Blog")
comp_blog = gdb.nodes.create(name="Computer Blog")
trav_blog = gdb.nodes.create(name="Travel Blog")
gour_blog = gdb.nodes.create(name="Gourmet Blog")
cam_blog.labels.add("Blog")
comp_blog.labels.add("Blog")
trav_blog.labels.add("Blog")
gour_blog.labels.add("Blog")
# Relationの追加
alice.relationships.create("Own", cam_blog)
bob.relationships.create("Own", comp_blog)
ken.relationships.create("Own", trav_blog)
alice.relationships.create("Subscribe", trav_blog)
alice.relationships.create("Subscribe", gour_blog)
bob.relationships.create("Subscribe", cam_blog)
ken.relationships.create("Subscribe", comp_blog)
また、ブラウザで http://localhost:7474/browser/ にアクセスして下記のクエリを投げると、
MATCH (n)-[r]-(m) RETURN n, r, m
こんなグラフが表示されます。なかなか分かりやすいと思います。「グラフデータベースは関係性がリレーショナルデータベースよりもわかりやすい」、と言われるゆえんですねw
#3. Cypherファーストステップ#
Cypherの基本的な書き方について例を幾つか挙げてみようと思います。
赤丸で示した下記のBob, Alice, Kenが選択されます。
match (n:Person) RETURN n
(※ 赤枠は分かりやすさのために追加したものでNeo4Jのブラウザ画面でこの表示になるわけではありません)
今度はBlogのノードが選択されます。
match (n:Blog) RETURN n
このCypherクエリはBobだけを抽出します。
MATCH (b:Person {name:'Bob'}) RETURN b
関係も一緒に選択します。下記の場合はOwnの関係があるもののみが対象です。
MATCH (p:Person)-[r:Own]->(b:Blog) RETURN p,r,b;
最後にランダムにPersonノードとBlogノードを100個ずつ生成して、そこに500のSubscribe関係を付与したグラフを生成して表示してみます。
import numpy.random as rd
l = 100
person_list = []
blog_list = []
for i in range(l):
p = gdb.nodes.create(name="person_%d"%i)
p.labels.add("Person")
b = gdb.nodes.create(name="Blog_%d"%i)
b.labels.add("Blog")
person_list.append(p)
blog_list.append(b)
r1 = range(len(person_list))
rd.shuffle(r1)
for i in range(len(blog_list)):
blog_list[i].relationships.create("Own", person_list[r1[i]])
r2 = range(l) * 5
rd.shuffle(r2)
r3 = range(l) * 5
rd.shuffle(r3)
for i,j in zip(r2, r3):
person_list[i].relationships.create("Subscribe", blog_list[j])
カオスですね!
#3.Networkxで描画#
iCypherをインストールします。
pip install ipython-cypher
下記のコードでnetworkxでグラフ化できます。
%load_ext cypher
%matplotlib inline
import networkx as nx
import matplotlib.pyplot as plt
result = %%cypher http://<ユーザーID>:<パスワード>@localhost:7474/db/data/ MATCH (n)-[r]-(m) RETURN n,r,m;
node_map ={'Person':'#22FF99', 'Blog': '#6622FF' }
node_label={'Person':'Person', 'Blog': 'Blog' }
g = result.get_graph()
pos=nx.get_node_attributes(g,'pos')
plt.figure(figsize=(15,15))
nx.draw(g, node_color=[node_map[g.node[n]['labels'][0]] for n in g],node_size=80, width=0.5, edge_color='#999999')