読者です 読者をやめる 読者になる 読者になる

javaからOrientDBを操作してみる(RawGraphDatabase編)

OrientDB

あんまりドキュメントがないのでとりあえずざっくり触ってみるだけです!
OrientDB - JavaAPI


データベースのタイプが複数あって、どれを使うかでJava側の実装が変わる雰囲気。
ざっと見た感じ「RawGraphDatabase」がよさげなのでこいつをいじってみます。
GraphDatabaseRaw


とりあえず管理クラス的なものを作ってみる。

public class OrientDBManager {

	private OGraphDatabasePool oGraphDatabasePool = OGraphDatabasePool.global();
	private static final String USER = "admin";
	private static final String PASS = "admin";
	private static final String GRAPH = "remote:xxx.xxx.xxx.xxx/graph5";

	/**
	 * 終了時に実行<br>
	 * プールを開放する
	 */
	public void destroy() {
		System.out.println("OrientDBManager destroy start...");
		if (oGraphDatabasePool != null) {
			oGraphDatabasePool.close();
		}
		System.out.println("OrientDBManager destroy end.");
	}
}


早速こいつを使って最低限の実装をしてみます。
今回触るデータタイプの場合、基本的にはcom.orientechnologies.orient.core.db.graph.OGraphDatabaseを操作する感じになるみたいです。
今回はユーザー同士がフォローしあうだけみたいなものを想定したものを作ってみます。
流れは以下のような感じ。

  1. 指定したname属性とdate属性を持つvertexを作成(同じnameを持つvertexが既に存在する場合はエラー)
  2. vertex同士を繋ぐ「follow」というlabelとdate属性を持ったedgeを作成
  3. 指定したvertexを始点とするedgeを作成された順に表示


まず始めにvertexの作成メソッド。

public void createVertex(Map<String , Object> params) {
	OGraphDatabase db = null;
	try {
		// DBに接続
		db = oGraphDatabasePool.acquire(GRAPH, USER, PASS);
		// vertexを作成し、フィールドを設定
		ODocument vertex = db.createVertex();
		for (String key : params.keySet()) {
			vertex.field(key, params.get(key));
		}
		// 保存
		vertex.save();
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		if (db != null) {
			db.close();
		}
	}
}


次にvertexの取得用メソッド。

public ODocument selectVertex(String name) {
	ODocument result = null;
	OGraphDatabase db = null;
	try {
		db = oGraphDatabasePool.acquire(GRAPH, USER, PASS);
		// クエリの作成
		String query = "select from " + OGraphDatabase.VERTEX_CLASS_NAME + " where name = '" + name + "' limit 1";
		// クエリを発行
		List<ODocument> list = db.query(new OSQLSynchQuery<ODocument>(query));
		// 結果取得
		if(list != null && list.size() > 0) {
			result = list.get(0);
		}
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		if (db != null) {
			db.close();
		}
	}
	return result;
}


次はedgeに移ります。まずは作成。

public void createEdge(ORID rid, ORID targetRid, String label, Map<String, Object> params) {
	OGraphDatabase db = null;
	try {
		db = oGraphDatabasePool.acquire(GRAPH, USER, PASS);
		// edgeの作成
		ODocument edge = db.createEdge(rid, targetRid).field(OGraphDatabase.LABEL, label);
		// paramsが存在すればedgeのプロパティとして設定
		if (params != null) {
			for (String key : params.keySet()) {
				edge.field(key, params.get(key));
			}
		}
		// edgeを保存
		edge.save();
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		if (db != null) {
			db.close();
		}
	}
}

引数にあるORIDはOrientDBで追加時に自動的に振られるIDで、select時はRIDと表示されています。


次はedgeの取得。

public List<ODocument> selectEdgeListOut(ORID outRid, int skip, int limit, String orderBy) {
	List<ODocument> list = null;
	OGraphDatabase db = null;
	try {
		db = oGraphDatabasePool.acquire(GRAPH, USER, PASS);
		String query = "select from " + OGraphDatabase.EDGE_CLASS_NAME
				+ " where out = " + outRid.toString() + " order by " + orderBy
				+" desc skip " + skip + " limit " + limit;
		// 並び替えの条件が指定されていれば設定
		if (orderBy != null) {
			query += " order by " + orderBy + " desc";
		}
		list = db.query(new OSQLSynchQuery<ODocument>(query));

	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		if (db != null) {
			db.close();
		}
	}
	return list;
}

descとかもろもろベタ書きやめたいところですが、とりあえずという感じで…。


これでとりあえず準備ができたので、それぞれのメソッドを実行してみます。
とりあえずvertexとedgeの作成。

public void createVertexTest() {
	OrientDBManager mgr = null;
	String name = "user1";
	try {
		// マネージャの生成
		mgr = new OrientDBManager();
		// vertexを取得
		ODocument vaetex = mgr.selectVertex(name);
		// 既に同じnameのvertexが存在した場合は終了
		if (vaetex != null) {
			return;
		}
		// プロパティの設定
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("name", name);
		params.put("date", new Date());
		// vertexの作成を実行
		mgr.createVertex(params);
	} finally {
		// プールの終了処理
		if (mgr != null) {
			mgr.destroy();
		}
	}
}

public void createEdgeTest() {
	OrientDBManager mgr = null;
	String outName = "user1";
	String inName = "user2";
	try {
		mgr = new OrientDBManager();
		// 始点の取得
		ODocument outVertex = mgr.selectDocumentByName(outName);
		// 存在しなければ終了
		if (outVertex == null) {
			System.out.println("rid is empty.");
			return;
		}
		// 終点の取得
		ODocument inVertex  = mgr.selectDocumentByName(inName);
		if (inVertex == null) {
			return;
		}
		// フィルターの設定
		String[] labels = {"follow"};
		// 同じedgeが存在した場合は終了
		ODocument edge = mgr.selectEdge(outVertex, inVertex, labels);
		if (edge != null) {
			return;
		}
		// ラベルとプロパティの設定
		String label = "follow";
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("date", new Date());
		// edgeの作成
		mgr.createEdge(outVertex.getIdentity(), inVertex.getIdentity(), label, params);
	} finally {
		if (mgr != null) {
			mgr.destroy();
		}
	}
}

ODocument#getIdentityでRIDが取得できます。


こいつらを何回か値を変えて叩く叩く叩く。
コンソールで確認すると以下のような状態になりました。

> select from OGraphVertex
---+---------+--------------------+--------------------
  #| RID     |name                |date                
---+---------+--------------------+--------------------
  0|     #6:0|user1               |2012-04-16 20:48:17 
  1|     #6:1|user2               |2012-04-16 20:49:10 
  2|     #6:2|user3               |2012-04-16 20:49:17 
  3|     #6:3|user4               |2012-04-16 20:49:22 
  4|     #6:4|user5               |2012-04-16 20:49:27 
---+---------+--------------------+--------------------
5 item(s) found. Query executed in 0.0050 sec(s).

> select from OGraphEdge
---+---------+--------------------+--------------------+--------------------+--------------------
  #| RID     |out                 |in                  |label               |date                
---+---------+--------------------+--------------------+--------------------+--------------------
  0|     #7:0|#6:0                |#6:1                |follow              |2012-04-16 20:49:57 
  1|     #7:1|#6:0                |#6:2                |follow              |2012-04-16 20:50:11 
  2|     #7:2|#6:0                |#6:4                |follow              |2012-04-16 20:50:26 
  3|     #7:3|#6:0                |#6:3                |follow              |2012-04-16 20:50:33 
---+---------+--------------------+--------------------+--------------------+--------------------
4 item(s) found. Query executed in 0.0060 sec(s).


最後に始点がname=user1のvertexであり、かつlabelがfollowのedgeをdateの降順で取得します。

public void selectEdgeTest() {
	OrientDBManager mgr = null;
	String outName = "user1";
	try {
		mgr = new OrientDBManager();
		ODocument outVertex = mgr.selectVertex(outName);
		if (outVertex == null) {
			return;
		}
		int limit = 10;
		// edgeのリストを取得
		List<ODocument> list = mgr.selectEdgeListOut(outVertex.getIdentity(), 0, limit, "date");
		// inのRIDとdateを表示
		for (ODocument od : list) {
			System.out.println(od.field("in", ORID.class));
			System.out.println(od.field("date"));
			System.out.println("------");
		}
	} finally {
		if (mgr != null) {
			mgr.destroy();
		}
	}
}


結果は…!

#6:3
Mon Apr 16 20:50:33 JST 2012
------
#6:4
Mon Apr 16 20:50:26 JST 2012
------
#6:2
Mon Apr 16 20:50:11 JST 2012
------
#6:1
Mon Apr 16 20:49:57 JST 2012
------

ヤターウゴイタヨー。
ちゃんとdateの降順で取得できてますね!
ここまで取得したらinのRIDをもとにvertexを取得したいところ。
プロパティを条件としたvertexの取得は上でやってるので、RIDを条件とした場合のクエリが分かればちょっと書き換えるだけで実現できます。
ちなみにRIDを条件とした場合のクエリは以下のようなかんじ。

select from ographvertex where @rid = #6:0;

かんたん!
OrientDBのSQLについては以下なんかを。
OrientDB - SQL


ちなみにテストメソッドでlimitとskipがあるのにあんまり意味をなしてないのは事情があります…。
skipは現在の最新である1.0rc9で実装されたもので、軽く触った感じ割とまともに動いてる雰囲気なんですけど、order by句と組み合わせると挙動がおかしくなります。ていうか多分無視されてます。
報告しようかなー。他になんかやりようあるのかなー。うーんうーん。


問題はありつつとりあえずjavaからOrientDBを操作出来るようになりました。
プール周りが若干不安だったり、SQLベタで書くのがアレなのとStringをシングルクォーテーションでくくるのが面倒だったりするのでmyBatisみたいな感覚で、せめてpreparedStatementみたいな感覚で書きたいとか色々あるので、実サービスに乗せる場合はそのへん考えないとまずそう。

あとはキャッシュが効いてるのかなんなのか、コンソールに接続した状態でjavaからテーブル作るとコンソール側に反映されてなかったりするのでそのへんも要調査というかんじ。


今回RawGraphDatabaseを触ったんですけど、TinkerPopのやつもちょっと気になるので、今度そっちもやってみようかなーと。思ったり思わなかったりします。
これで操作しておくとTinkerPopのプロダクトからの操作がしやすい形でデータが保存されるんだろうなーとか。そうじゃないかもなーとか。
資料少ないぞOrientDB。英語読めない僕でもいけるのかOrientDB。

スポンサーリンク