グラフDBのNeo4jで関連キーワード検索を試してみる

最近子供と風呂に入っては「肩まで浸かって指で6bit(63)まで数えよう」と教えています。
2進数なら両手で1023まで数えられて便利なんじゃないかと思ってます。CTOの花村です。

少し前に待鳥さんにグラフデータベースの存在を教えてもらいました。
学生時代に数学系研究室おり、ちょっとだけグラフ理論をかじった経験があり、
興味があったので実際にグラフ構造のデータを入れてつかってみました。

このエントリーは実際にNeo4jにデータを投入してみるところまでやったというものであり、
具体的な環境構築やチューニングの話はしておりませんのであらかじめご了承ください。

Neo4jに関して

グラフ構造のデータの扱いに優れたグラフデータベースで、
関連性に特化した検索で優位性があるとのこと。
RDBでリレーションを貼る構成に比べると、高いスケーラビリティを実現しています。
グラフデータを扱うのであれば、現状Neo4j一択のようです(2016年11月現在)

Neo4j: The World’s Leading Graph Database

環境構築

環境構築に関しては以下のQiitaがよくまとまっていたのでそちらを参考にさせていただきました。

Neo4j Docker版を動かしてみました

起動するだけであれば、dockerの入っている環境で以下を実行すればおしまいです。

$ docker run
--publish=7474:7474 --publish=7687:7687
--volume=$HOME/Workspace/neo4j/data:/data
neo4j

またpythonからNeo4jにデータを入れるためにpy2neoというパッケージを利用しました。

$ pip install py2neo

画面

上記コマンドで起動させればlocalhost:7474で起動するはずです。

neo4j

ここからチュートリアルや、サンプルデータで遊ぶことができます。

実際のデータを投入してみる。

数十分も遊ぶとサンプルに飽きるので、さっそくデータをいれてみましょう。

4次元立体の頂点情報をCSVで入れる

4次元立体を人間が知覚するのは難しいですが、座標をとるのは非常に簡単(xyzにwを足すだけ)です。またそれを、3次元 -> 2次元と次元を落として投影することで形を見ることもできます。ためしに4次元の正多胞体(3次元の正多面体にあたるもの)の構造を入力してみます。頂点情報と辺情報があれば描画できるのでグラフデータベースと相性が良いです。

正多胞体の頂点と辺のCSVは以下のサイトからお借りしました。
ACTIVITIES OF DR. TAKASHI YOSHINO

dockerで起動したせいかlocalのCSVファイルの読み込みがうまくいかなかったので、gistにuploadしてからurlで読み込むことにしました。CSVは接続されるべき頂点のIDが2つずつ記載されている形式でしたので、このCSVをNeo4jのUIから流し込み、グラフ構造を登録することができます。入力にはNeo4jの CypherQL (Cypher Query Language) というグラフクエリ言語を使用します。

LOAD CSV FROM "https://gist.github.com/hanasoo/a30f2b65de106df90bc7b551ec9e4bac" AS row
MERGE (n1:Cell8Node {id: toInt(row[0])})
MERGE (n2:Cell8Node {id: toInt(row[1])})
MERGE (n1)-[:E]-(n2)

最初の行でCSVをロード、2行目と3行目で頂点を宣言し変数に格納(n1, n2)。
4行目が独特ですが、n1とn2を辺で結ぶ処理を行っています。
MERGE はデータが存在しなければ追加します。よくある get_or_insert の処理です。
同じ頂点が複数回よばれるのでこの処理を追加しました。

グラフを描画してみる

正8胞体

neo4j-2

4次元立方体とか超立方体とかテッセラクトとか。
よく見ると3次元の立方体が8個あるのが確認できます。
個人的には一番お世話になった、思い入れのある立体。

正120胞体

eee89674-2de6-2499-0199-3be12b329b0f

よく見ると3次元の正12面体が120個くっついているのがみえるでしょうか。
正12面体のトリッキーな構成美がそのまま4次元になっていて、飽きの来ない形をしています。

正600胞体

b90b548f-379b-6cb2-2992-66ae5d95f9a4

よく見ると4面体が600個くっついているのがみえるでしょうか。みえないでしょうか。
字面的にラスボス的なポジションにいながらサイズも小さく、絵的に残念な感じがします。

実際に業務で使ってみる

ビザスクでは登録いただいたアドバイザー様の知見データベースとして持っています。実際に知見をキーワード検索する際には、単純にキーワードの検索結果をとるだけでなく、関連キーワードでの検索結果も利用しています。今回試しに、実際に検索されるキーワードとその関連キーワード、そのキーワードを含む知見と、そのユーザーさんまで、というグラフ構造をNeo4jに入れてみました。

pythonから知見データを投入する

以下はデータを流し込んだ際のサンプルです。
user_topic_mapping が、 user と topic (知見)の組み合わせの情報、
topic_word_mapping が、 topic (知見)と word (保持キーワード)の組み合わせの情報です。
元データの都合上このようなデータを渡していますが他に方法あったかもしれません。

py2neo.authenticateで接続して先程のCypherQLでデータを入力していきます。
検索キーワードを関連キーワードと紐付ける処理はデータがCSVだったので先程のやり方で入力しています。

さてこれで検索キーワードの関連情報から、ユーザーを検索できるようになりました。
実際に検索するクエリは以下のように書くことができました。

知見データを検索してみる

MATCH (m:MetaKeyword)-[]->(k:Keyword)-[]->(t:Topic)<-[:CONTAINS]-(u)
WHERE m.word="エンジン"
RETURN DISTINCT m,k,t,u

エンジンという検索キーワード(MetaKeyword)に関してのリレーションを矢印で繋いでいきます。
Neo4jは有向グラフなので、矢印の向きも注意する必要があります。

実際の検索結果を描画してみると以下のようになりました。
cover

赤が起点となるキーワードで、ピンクが関連キーワード、緑が知見、青がアドバイザー様です。
(上記画像はデモ用に、WHERE句を調整しています)

まとめ

  • CypherQLの表記方法が最初とっつきにくかったですが、よく見ればクエリがそのままグラフになっていて理解しやすい
  • グラフ構造を実際に可視化してくれるインターフェースは便利。見た目派手でおもしろい。
  • 実際の業務レベルで可視化をどこまで使うかは不明
  • レポーティングには便利なのかも
  • ライブラリがすでに豊富あるので現行システムとのつなぎこみは容易そう

一緒にやってくれる仲間を募集しています!

エンジニアを募集しています

ビザスクでは、エンジニアとして働きたい方を募集しています。
ご興味のある方は下記よりお気軽にご連絡ください。