インデックスを使用した検索
neo4jではApocという拡張コンポーネントパッケージを使用することでLuceneを使用した検索を行うことができる。これらの拡張機能を使用するにはneo4jのダウンロードページからneo4j-apoc-1.0.zipを取得し、展開したアーカイブのlibディレクトリに格納されているJARファイルをクラスパスに追加する必要がある。
Mavenで使用する場合はpom.xmlに以下の記述を追加しよう。
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-apoc</artifactId>
<version>1.0</version>
<type>pom</type>
</dependency>
インデックスは自動では作成されず、プログラム中でIndexServiceを使用して明示的に作成する必要がある。以下の例で使用しているLuceneIndexServiceはLuceneを使用してインデックスを作成するためのサービスで、完全一致による検索を行うことができる。
// DBの保存先ディレクトリを指定してDBのインスタンスを生成
GraphDatabaseService graphDb = new EmbeddedGraphDatabase("db");
// トランザクションを開始
Transaction tx = graphDb.beginTx();
// インデックスサービス
IndexService index = new LuceneIndexService( graphDb );
try {
Node personNode = graphDb.createNode();
personNode.setProperty( "name", "Naoki Takezoe" );
// インデックスを作成
index.index( personNode, "name", personNode.getProperty( "name" ) );
// インデックスを使用して一致するノードのリストを取得
IndexHits<Node> nodeList = index.getNodes("name", "Naoki Takezoe");
for(Node node: nodeList){
System.out.println(node.getProperty("name"));
}
// インデックスを使用して1件取得
Node node = index.getSingleNode("name", "Naoki Takezoe");
System.out.println(node.getProperty("name"));
// 処理が成功
tx.success();
} catch(Exception ex){
// 処理が失敗
tx.failure();
} finally {
// トランザクションを終了してDBをシャットダウン
tx.finish();
index.shutdown();
graphDb.shutdown();
}
LuceneIndexServiceの代わりにLuceneFulltextIndexServiceを使用してインデックスを作成することで全文検索も可能だ。部分一致で検索したいフィールドがある場合はこちらを使用するといいだろう。
Javaオブジェクトへのマッピング
neo4jではNodeオブジェクトとRelationshipオブジェクトを使用してグラフを表現するが、jo4neoを使用することでグラフをJavaオブジェクトにマッピングすることができる。
jo4neoを使用するにはneo4jのApocのJARファイルに加えてjo4neoのWebサイトからダウンロードしたJARファイルをクラスパスに追加する必要がある。Mavenで使用する場合はpom.xmlに以下の記述を追加しよう。
<repositories>
<repository>
<id>jo4neo-repository</id>
<url>http://jo4neo.googlecode.com/svn/trunk/repo/</url>
</repository>
</repositories>
...
<dependencies>
<dependency>
<groupId>thewebsemantic</groupId>
<artifactId>jo4neo</artifactId>
<version>0.4.1</version>
</dependency>
...
</dependencies>
jo4neoでは以下のように@neoアノテーションを付与したJavaBeanでノードを定義することができる。関連を定義するには他のオブジェクトやjava.util.Collection型のフィールドを定義して@neoアノテーションを付与しておけばよい。また、JavaBeanには必ずjo4neo.Nodeid型のtransientフィールドを定義しておく必要があるので注意してほしい。
public class Employee {
public transient Nodeid neo;
@neo(index=true)
public String name;
@neo(index=true)
public String mail;
}
jo4neoで指定可能なアノテーションには以下のようなものがある。
属性名 | 説明 |
---|---|
@neo String name; | フィールドをノードのプロパティとして永続化する |
@neo Person friend; | 関連するオブジェクトをノードとリレーションとして永続化する |
String misc; | フィールドを永続化しない |
@neo(index=true) String name; | フィールドを永続化し、インデックスを作成する |
@neo(fulltext=true) String content; | フィールドを永続化し、全文検索インデックスを作成する |
@neo("HAS_JOB") Job job; | リレーションを指定した名前で永続化する |
@embed Address address; | 関連するオブジェクトをリレーションではなくバイナリシリアライズして永続化する |
このノードをデータベースに永続化するには以下のようにする。jo4netが提供するObjectGraphというインタフェースを使用して操作を行っている。検索や削除もこのインタフェースで行うことができる。
GraphDatabaseService graphDb = new EmbeddedGraphDatabase("db");
ObjectGraph graph = ObjectGraphFactory.instance().get(graphDb);
try {
Person person = new Person();
person.name = "Naoki Takezoe";
person.mail = "takezoen@gmail.com";
// オブジェクトを永続化
graph.persist(person);
} finally {
graph.close();
graphDb.shutdown();
}
直接neo4jを用いる場合と同様、jo4neoでも検索にはいくつかの方法がある。
// オブジェクトの型を指定して全件取得
Collection<Person> list = graph.get(Person.class);
// IDを指定して1件取得
Person person = graph.get(Person.class, 1);
// 条件を指定して検索
Employee emp = new Employee();
emp = graph.find(emp).where(emp.name).is("Naoki Takezoe").result();
このようにjo4neoを使用するとneo4jをオブジェクトデータベースとして使用することができる。また、インデックスの作成もアノテーションだけで指定することができる。スキーマを予め定義できる場合はNodeオブジェクトやRelationshipオブジェクトを直接扱うよりもタイプセーフなJavaBeanのほうが扱いやすいだろう。neo4jにおけるオブジェクト/グラフマッパーとして積極的にjo4neoを活用したいところだ。
なお、jo4neoはJavaBeanへのマッピングを行うために各ノードにjo4neo.Nodeidというプロパティを自動的に追加する。そのためjo4netを使わずに作成した既存のデータベースをJavaBeanにマッピングすることはできないので注意してほしい。