Neo4jで遊んでみた
概要
Neo4jというDBをご存知でしょうか? neo4j.com
自分は名前だけは知っていたのですが、触ったことがなかったので試しに遊んでみることにしました
Neo4jとは
Neo4jはグラフ型のDBです
ここでいうグラフとは、グラフ理論のことでノード(点)とエッジ(辺)で表されるデータのことをいいます
Neo4jはグラフを扱うのに特化したDBで、RDBとはかなり異なるDBになっています
その分、グラフに関する操作はやりやすい設計になっており、グラフで表されるデータの複雑な操作や分析がやりやすくなることが期待できます
今回扱うテーマ
何かテーマを用意しないと面白くないので、今回は「東京の駅で無くなったら一番困る駅は?」というのをテーマにしてみます
東京って駅がたくさんありますよね
その中でも無くなったら一番困る駅ってどこでしょうか?
おそらく、新宿や東京や品川あたりが候補に出てくると思います
今回はそれをグラフ理論の考え方に基づいて調べていきましょう
このテーマをグラフ理論の言葉で言い換えるとこうなります
「東京の駅で媒介中心性が一番高いのはどの駅?」
媒介中心性(Betweenness centrality)とは、あるノードがどれくらい他のノード間の最短経路になっているかを表す指標です
ざっくり言ってしまうと、「そのノードが無くなったときに、どれくらい遠回りをする羽目になるか」を表します
今回の東京の駅の例にはぴったりの指標ですね
媒介中心性の詳しい説明や定義はWikipediaがよくまとまっていたので、そちらを参照してください
やった作業の流れ
ここからは実際にNeo4jを使って媒介中心性を求めていきます
1.データを用意する
まずは駅のデータが無ければ始まりません
今回は駅データ.jpのデータを使わせていただきました
無料会員登録をすれば、駅の情報とどの駅がつながっているかのデータをダウンロードすることができます
Neo4jで読み込ませるため、ダウンロードしてきたデータを加工してこんなcsvにしておきます
各行は電車でつながっている駅を表します
$ head join_list.csv station_name_x,station_name_y 東京,新橋 新橋,品川 大崎,五反田 五反田,目黒 目黒,恵比寿 恵比寿,渋谷 渋谷,原宿 原宿,代々木 代々木,新宿
2. Neo4jを起動
データが用意できたので、Neo4jを起動します
今回はお手軽にdockerで起動します
docker run \ --name testneo4j \ -p7474:7474 -p7687:7687 \ -d \ -v $HOME/neo4j/data:/data \ -v $HOME/neo4j/logs:/logs \ -v $HOME/neo4j/import:/var/lib/neo4j/import \ -v $HOME/neo4j/plugins:/plugins \ --env NEO4J_AUTH=neo4j/test \ --env NEO4JLABS_PLUGINS='["graph-data-science"]' \ neo4j:latest
dockerの起動オプションはこちらを参考にしました
How-To: Run Neo4j in Docker - Developer Guides
また、dockerではなくバイナリが良いという方はこちらからダウンロードできます
Neo4j Desktop Download - Launch and Manage Neo4j Databases
Neo4jを起動して、ブラウザでlocalhost:7474にアクセスするとこんな画面が出てきます
ここからクエリを入力することで、データをロードしたりデータに対する操作を行うことができます
3. Neo4jにデータをロード
手順1で作成したcsvをNeo4jにロードします
Neo4jではSQLではなく、Cypher queryというクエリでDBを操作します
データをロードするクエリはこのような形になっています
LOAD CSV WITH HEADERS FROM 'file:///join_list.csv' AS row MERGE (s1:Station {name: row.station_name_x}) MERGE (s2:Station {name: row.station_name_y}) MERGE (s1)-[r:CONNECTED]->(s2) RETURN s1,r,s2
MERGE (s1:Station {name: row.station_name_x})
で駅の情報をノードとして登録し、 MERGE (s1)-[r:CONNECTED]->(s2)
で駅と駅の間をエッジで繋いでいます
このクエリをNeo4j上で実行すると、DBにデータがロードされるとともに、グラフの形を視覚的に確認できます
実行した結果をすぐに確認できるのは便利ですね
4. 媒介中心性を計算
ロードしたデータを使って媒介中心性を計算します
Neo4jにはGraph Data Science Library (GDS)というライブラリが付属しており、中心性のような基本的な計算は簡単にできるようになっています
今回はこれを使っていきます
媒介中心性を計算するクエリはこのようになります
CALL gds.graph.create('stationGraph', 'Station', {CONNECTED: {orientation: 'UNDIRECTED'}}) CALL gds.betweenness.stream('stationGraph') YIELD nodeId, score RETURN gds.util.asNode(nodeId).name AS name, score ORDER BY score DESC
gds.graph.create
で計算用にグラフをメモリにロードし、gds.betweenness.stream
で媒介中心性を計算するイメージです
このクエリを実行した結果は以下のようになりました
╒════════════════╤══════════════════╕ │"name" │"score" │ ╞════════════════╪══════════════════╡ │"新宿" │97896.80592681374 │ ├────────────────┼──────────────────┤ │"東京" │61886.951565744006│ ├────────────────┼──────────────────┤ │"吉祥寺" │53840.41960233269 │ ├────────────────┼──────────────────┤ │"三鷹" │49887.98300653595 │ ├────────────────┼──────────────────┤ │"国分寺" │47959.88300653591 │ ├────────────────┼──────────────────┤ (以下省略)
新宿、東京のスコアが高いのは予想通りですが、吉祥寺や三鷹が上位に入ってくるのは少し意外ですね
感想
媒介中心性の計算までやることで、Neo4jの大まかな使い方は把握できました
今回の規模だとPythonでNetoworkXのようなグラフに特化したライブラリを使う方が便利です
ただ、例えば業務で複数の人が同じデータを参照する場合はNeo4jに格納した方が、効率的に作業が進められそうですね
補足
- dockerなどを使わず、とりあえずNeo4j触りたいだけのときはブラウザからsandbox版を試すことができます
- Neo4jの雰囲気だけ知りたいという方はぜひ試してみてください
- 今回はGDSがあったので、全てNeo4j内で操作が完結しましたが、実際はアプリケーションからDBの値を読んで、色々操作したいという場合もあると思います
- そのような場合は、各言語のドライバがあるのでそれを使えば実現可能です
- Neo4j Download Center - Neo4j Graph Database Platform