neo4jを使ってみる その1

neo4jは組み込み型のグラフデータベースエンジンとのこと。

グラフ(ネットワーク)データベースではノードとリレーションでデータを表現していきます。リレーショナルデータベースと違って各ノードは自由なスキーマを持てるのと、検索するときはノードをたどって目的のノードを探すので、RDBMSと比べると自由度が高い反面、検索はごりごりロジックを組む必要があります。
というわけで、まずはノードを追加するコード。

// DBの保存先ディレクトリを指定してDBのインスタンスを生成
GraphDatabaseService graphDb = new EmbeddedGraphDatabase("db");

// トランザクションを開始
Transaction tx = graphDb.beginTx();

try {
  // ノードを作成
  Node firstNode = graphDb.createNode();
  firstNode.setProperty("name", "Naoki Takezoe");
  firstNode.setProperty("mail", "takezoe@gmail.com");
  
  // 処理が成功
  tx.success();

} catch(Exception ex){
  // 処理が失敗
  tx.failure();
  throw ex;

} finally {
  // トランザクションを終了してDBをシャットダウン
  tx.finish();
  graphDb.shutdown();
}

nao4jはトランザクションをサポートしており、beginTx()しておかないと検索も更新もできません。tx.success()でいわゆるコミット、tx.failure()でロールバックになるみたいです。
ちゃんとノードが追加されているかを確認するために、データベース内のノードを全部表示してみます。

// すべてのノードを表示
for(Node node: graphDb.getAllNodes()){
  System.out.println("ID=" + node.getId());
  for(String key: node.getPropertyKeys()){
    System.out.println(key + "=" + node.getProperty(key));
  }
  System.out.println("--");
}

すると以下のように出力されました。とりあえずちゃんと動いているっぽいです。

ID=0
--
ID=1
mail=takezoe@gmail.com
name=Naoki Takezoe
--

続きます。

neo4jを使ってみる その2

ノードとノードをつないでグラフを作ってみます。
ノード間のリレーションはRelationshipオブジェクトで表現されます。試しに社畜と会社の関係を表してみましょう。

// 関連のタイプを表現する列挙型
public enum MyRelationshipTypes implements RelationshipType {
  WORKS_AT
}

...

// 1つめのノードを作成
Node emp= graphDb.createNode();
emp.setProperty("name", "Naoki Takezoe");

// 2つめのノードを作成
Node company = graphDb.createNode();
company.setProperty("name", "NTT DATA INTELLILINK");

// 1つめのノードから2つめのノードへの関連を定義
Relationship relationship = emp.createRelationshipTo(
  company, MyRelationshipTypes.WORKS_AT);

前回のサンプルでは全ノードをループで出力しましたが、neo4jにはリレーションをたどってノードをトラバースする機能があるのでこれを試してみます。

// 基点となるノードを取得
Node company = ...

// EMPLOYSの関連をたどるトラバーサ
Traverser traverser = company.traverse(
  Order.DEPTH_FIRST,
  StopEvaluator.END_OF_GRAPH,
  ReturnableEvaluator.ALL_BUT_START_NODE,
  MyRelationshipTypes.EMPLOYS,
  Direction.OUTGOING);

for(Node emp: traverser){
  ...
}

単純に関連をたどるだけでなく、ReturnableEvaluatorを拡張することでフィルタリングみたいなことが可能です。あと、拡張機能になりますが、IndexServiceというものを使うことでプロパティでの検索を行うこともできます。インデックスと検索する値を指定すると一致するノードを取得することができます。
とりあえず基本機能はこんなところでしょうか。
あと、jo4neoというオブジェクト/グラフマッパーや、Neoclipseなんていうneo4jのDBの中身を参照・操作するためのEclipseプラグインなんかもあるようです。