JavaでJanusGraphを組み込む方法


JanusGraphはPythonやJavascriptなど、様々な言語用のドライバを提供しており、それらの言語からGremlinサーバーにアクセスできるようになっているが、DB自体を組み込んだ(Embeddedな)アプリケーションを作ろうと思った場合、選択肢は事実上JavaとGroovyに限られる。

今回はJavaでJanusGraph(with Berkeley DB)を組み込んだアプリケーションの作り方を説明する。

DBの設定と永続化データはそれぞれディレクトリに保存されるが、それ以外は単体で完結するシンプルなアプリ構成。

JDKのインストールと環境変数

JanusGraphを動かすだけならJREだけでも良かったが、開発を行うのであればJDKが必要になる。バージョンはJava 8となる。Oracleからダウンロードするとアカウントの登録が必要になるみたいなので、今回はAdoptOpenJDKを選択した。

URLにアクセスし、1.でOpenJDK 8 (LTS)を選択し、2.でHotSpotを選択する(両方ともデフォルト)。表示されるファイルの中から、自分のOSに合うJDKをダウンロードする。

私が使用したのはVersion jdk8u242-b08(8.0.242.08)、Windows x64用。

インストール方法は割愛する。インストールしたら、JDKのディレクトリを環境変数JAVA_HOMEとして登録する。私の場合だと以下のようになった。

JAVA_HOME=c:\Program Files\AdoptOpenJDK\jdk-8.0.242.08-hotspot

Apache NetBeans

開発に使うIDEは実際何でも良いが、ここではApache NetBeansを用いる方法を説明する。Eclipseも試してみたが、どうもすんなりいかなかったので諦めた次第。

インストール

ダウンロードは以下から行う。

Apache NetBeans

バージョンは11.3を選択した(Windows向けにはインストーラが用意されていたので)。なお、環境変数JAVA_HOMEが設定されていないとインストール時にエラーが発生する。

インストーラはすべて標準の設定のまま進めてインストールを完了させた。

プロジェクトの作成

NetBeansを起動すると、以下のような画面が表示される。

メニューから「File」-「New Project...」を選択する。

初期状態でJava with MavenJava Applicationが選択されているので、そのまま「Next >」ボタンを押す。

初回だとPlugin等のダウンロードが必要だというメッセージが表示されるので、「Download and Activate」ボタンを押して進める。

次にプロジェクトの名前やディレクトリの場所を設定する。いずれも適当で構わない。全て確認したら「Finish」ボタンでプロジェクト作成を完了する。

依存関係の追加(JanusGraphの参照)

左上のProjectFilesServicesと並んでいるところから、Filesを選択して、プロジェクトに存在するファイルのツリーを表示させる。

pom.xmlをダブルクリックして開く。ここにJanusGraphの依存情報を記載する。

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mycompany</groupId>
    <artifactId>janusexample</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.janusgraph</groupId>
            <artifactId>janusgraph-core</artifactId>
            <version>0.5.1</version>
        </dependency>
        <dependency>
            <groupId>org.janusgraph</groupId>
            <artifactId>janusgraph-berkeleyje</artifactId>
            <version>0.5.1</version>
        </dependency>
    </dependencies>
</project>

<dependencies>から</dependencies>までの間を追加した。janusgraph-coreはその名の通りJanusGraphのコア部分。janusgraph-berkeleyjeは組み込みBerkeley DBを使うために必要なライブラリ。その他、目的によって必要なライブラリを適宜追加しよう。

ライブラリ名(Artifact ID) 機能
janusgraph-all JanusGraph関係のライブラリを全部ひとまとめにしたもの。面倒だったらこれ1つpom.xmlに記述したら全部使える
janusgraph-backend-testutils バックエンドDBのテストコレクション
janusgraph-berkeleyje Berkeley DBをバックエンドにしたグラフDB実装
janusgraph-bigtable Google Cloud Bigtable用ドライバ
janusgraph-core JanusGraphのコアライブラリ群
janusgraph-cql Apache CassandraをバックエンドにしたグラフDB実装
janusgraph-dist 配布アーカイブ生成用(我々ユーザーが使うことは恐らくない)
janusgraph-doc ドキュメント
janusgraph-driver サーバーに接続するためのドライバ
janusgraph-es ElasticSearchをバックエンドにしたインデクシング実装
janusgraph-examples サンプルコード集
janusgraph-hadoop Apache Hadoopを用いたグラフ解析エンジン
janusgraph-hbase-parent Apache HBase関連のライブラリ
janusgraph-inmemory インメモリのグラフDB実装
janusgraph-lucene Luceneを用いたインデクシング実装
janusgraph-server JanusGraph製のGremlinサーバー実装
janusgraph-solr Apache Solrを用いたインデクシング実装
janusgraph-test テストコード

DB設定ファイルの追加

今回はBerkeley DBを組み込むようにしたいのでそのような設定ファイルをプロジェクトに追加する。

ファイルツリーのルートディレクトリにconfディレクトリを作成して、その中にファイルembedded.propertiesを追加する(ファイル名はなんでもよい)。




ファイルの中には以下の3行を書き込んでおく。

embedded.properties
gremlin.graph=org.janusgraph.core.JanusGraphFactory
storage.backend=berkeleyje
storage.directory=../db/berkeley

プログラムの作成

プログラムのソースコードを追加する。srcディレクトリの一番深いとこに作成されているプロジェクト名と同名のディレクトリに自前のクラスファイルを作成する。名前はJanusExample.javaとする。

コードの内容は最初は以下のようにする。

JanusExample.java
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.janusgraph.core.JanusGraphFactory;

public class JanusExample {
    public static void main(String args[])
    {
        Graph graph = JanusGraphFactory.open("conf/embedded.properties");
        System.out.println(graph.toString());
        graph.close();
    }
}

これはグラフを開いて閉じるだけの簡単なサンプル。ビルドはメニューの「Run」「Build Project」(WindowsだとF11キー)。実行は「Run」「Run Project」(WindowsだとF6キー)から行える。初回はMavenがいろいろとダウンロードするのでかなり時間がかかる。実行すると、dbディレクトリが生成され、そこにデータが記憶される。

クエリを行うにはGraphTraversalSourceを取得すればよい。戻り値の取得は静的型付け言語なのでなかなか大変だが、うまくやってほしい。

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.janusgraph.core.JanusGraphFactory;

public class JanusExample {
    public static void main(String args[])
    {
        Graph graph = JanusGraphFactory.open("conf/embedded.properties");
        GraphTraversalSource g = graph.traversal();
        // グラフを空にする
        g.V().drop().iterate();
        // 頂点を1個追加する
        g.addV("person").property("name", "bob").property("age", 27).iterate();
        // 変更を確定
        g.tx().commit();
        // 値を取り出すクエリを発行してみる
        List<Map<Object, Object>> result = g.V().valueMap("name", "age").toList();
        // 戻り値は [{name: ["bob"], age: [27]}] が返ってくるはず
        for(Map<Object, Object> vertex : result){
            // vertexは {name:["bob"], age: [27]} のはず
            ArrayList<String> names = (ArrayList<String>)vertex.get("name");  // ["bob"]を得る
            ArrayList<Integer> ages = (ArrayList<Integer>)vertex.get("age");  // [27]を得る
            String name = names.get(0);  //"bob"を得る
            Integer age = ages.get(0);  //27を得る
            System.out.printf("name: %s, age: %s\n", name, age);
        }
        // 頂点数を取り出すクエリを発行してみる
        Long count = g.V().count().next();
        System.out.printf("vertex count is %d\n", count);
        graph.close();
    }
}

結果は以下のようになるはず。

name: bob, age: 27
vertex count is 1

注意点:エラー発生時の対応

実行時に例外が発生した場合、プログラムが終了しない状態になっている。このまま再度実行しようとすると、グラフが開けないため、既存のプログラムを終了する必要がある。IDEの右下に×ボタンが表示されているので、押して終了させる。

使用するクラスの参照

コード中でimportされていないクラスを記述すると、下側に赤線で表示される。この部分にカーソルを合わせて、Alt+Enterを押すと、当該クラスをimportすることができる。この機能がないと正直Javaでの開発なんてやっていられない。

 おわりに

Javaに慣れていないと辛い所があるが(私自身Javaはド素人なので実際辛かった)、意外と簡単に組み込めてしまうので、使い勝手はかなりいいと思う。

スタンドアロンのアプリにするもよし、クエリの結果をJSONあたりに変換・送信して簡単な自作GraphDBサーバとして運用するもよし。

個人的にはPythonでこんな感じに組み込めたら理想的なのだが……。