/etc/apt/sources.list.d/pgdg.listを以下の内容で作成する。

リポジトリサインキーのインポートを行う。

リポジトリインデックスを更新する。

PostgreSQLをインストールする。

今やリレーショナルデータベース全盛の時代である。

どんなシステムもRDBなしには成り立たなくなっている。

しかし、RDBは本当に便利なのだろうか?

例えば、いまはやりのSNSを考えてみよう。

それぞれのユーザーは他のユーザーとネットワーク的につながりをもっている。

そして、そのつながりは友人関係だったり仕事仲間だったりする。

RDBではそれぞれの表の属性もあらかじめ定義される必要があり、後で属性を追加することは難しい。

しかし、SNSのような人間関係を表現するようなもので事前にデータ構造を予測することができるだろうか。

例えば最初は仕事で知り合った人間でも友人になることがあるし、恋人同士だったのが別れてしまって他人同士になってしまうこともあるだろう。

このようなダイナミックなデータ構造はRDBでは表現するのが難しいだろう。

しかし、グラフDBはこのような用途に向いたDBである。

例えば、Todoリストのデータを考えてみよう。

neo4j-011

上図の四角がノードとよばれるものでRDBでいう1レコードのデータを表す。

上の例ではタスク1ノードはタスク名、担当者名、タスク内容、期間という属性をもっていてそれぞれ値をもっている。

また、ノード間はリンクと呼ばれるもので接続される。

リンクは2ノード間の関係を表すものでどういう関係かをリンクの属性によって知ることができる。

ここではNEXTという属性によってタスクの順番を表現している。

このようにグラフDBはRDBとは根本的に違うデータ構造をもっている。

従って問い合わせもSQLではなくグラフをスキャンするAPIでデータを取り出す。

Neo4jはJavaで書かれたグラフDBライブラリである。

Neo4jを使ったプログラム例はこのようになる。

import org.neo4j.api.core.*;

public enum NeoTodoRelationTypes implements RelationshipType {
    NEXT
}
NeoService db = new EmbeddedNeo("var/base");
Node node1 = db.createNode();
node1.setProperty("name", "task1");
node1.setProperty("user", "鈴木");
node1.setProperty("content", "お仕事やってます");
node1.setProperty("due_date", "2009/6/30");
node2.setProperty("name", "task2");
node2.setProperty("user", "田中");
node2.setProperty("content", "あとは引き受けた!");
node2.setProperty("due_date", "2009/7/6");
 Relationship relation = node1.createRelationshipTo(node2,NeoTodoRelationTypes.NEXT);

import文でNeo4jライブラリをインポートしておく。

RelationshipTypeはリンクの属性を表すenumで「次へ」を表すNEXTを属性として持たせる。

EmbeddedNeoはNeo4j DBの初期化を行う。

次のcreateNodeでノードを一つ作成する。

そしてsetPropertyでノードに属性とデータを設定する。

次にノードを二つ作成しcreateRelationshipToでnode1とnode2のリンクを設定する。

これでリンクでつながった2つのノードの作成が完了する。

この要領でノード同士をつないでいけばノードのネットワークが出来上がる。

では、このネットワークからどのようにデータを取り出せばいいのだろうか

Transaction tx = db.beginTx();
try {
    Traverser tr = node1.traverse(Traverser.Order.BREADTH_FIRST,
                           StopEvaluator.END_OF_GRAPH,
                           ReturnableEvaluator.ALL,
                           NeoTodoRelationTypes.NEXT,
                           Direction.BOTH);
    Collection<node> node_list = tr.getAllNodes();
} finally {
    tx.finish();
}

Nodeクラスのtraverse APIでグラフネットワークをスキャンすることができる。

まず最初のノードのtraverseメソッドを呼ぶ。

1つ目の引数はスキャンする順番を指定するもので、BREADTH_FIRSTの意味は同じレベルにあるノードを最初にスキャンしてからより深いレベルのノードをスキャンするという意味である。

2つ目の引数はスキャンを停止する条件を指定する。

END_OF_GRAPHはグラフの最後まで来たら終了するという意味である。

3つ目の引数はどのノードの情報を返すかを指定する。

ALLなので全て返す設定になる。

4つ目はスキャンするリレーションタイプを指定する。

NEXTのリレーションタイプでつながっているノードをスキャンする。

最後はスキャンする方向を指定する

ノードからみてスキャンが他から入ってくる方向の場合はINCOMING、出て行く方向の場合はOUTGOINGとなる。

BOTHは両方の方向でのスキャンを指定する。

traverse実行後getAllNodesを呼ぶとスキャンされたノード情報がCollectionとして取得することができる。

後はイテレータで各ノードの情報をとればよい。

事前にデータ構造を決定することができてデータの整合性が重要なシステムにはRDBを使うべきだろう。

しかし、データ構造がダイナミックに変化するシステムではグラフDBを使った方が効率よく開発することができる。

これからは用途に合わせてデータベースも選ぶ時代になりつつあるのではないだろうか。