前回
の続きで、今回は OrientDB を Java から操作する。
Java API
OrientDB のコンポーネントは以下のようになっている。
データベースを操作する際には以下のAPIを利用することになる。
- Document API
- Object API
- Graph API
今回はこれらを簡単に見ていく。
JARの分類
orientdb の jar は以下のように分かれている。
JAR | 内容 | 説明 |
---|---|---|
orientdb-core-*.jar | コアライブラリ | 必ず必要 |
orientdb-client-*.jar | リモートクライアント | リモートサーバ経由で処理を行う場合に必要 |
orientdb-enterprise-*.jar | クライアントとサーバで共有のネットワークプロトコルの基本ライブラリ | リモートサーバ経由で処理を行う場合に必要 |
orientdb-server-*.jar | サーバコンポーネント | 組み込みサーバとして使う場合に必要 |
orientdb-tools-*.jar | コンソールとコンソールコマンド | 必要なし |
orientdb-object-*.jar | Object データベースのインターフェース | 必要時 |
orientdb-graphdb-*.jar | Graph データベースのインターフェース | 必要時 |
orientdb-distributed-*.jar | 追加プラグイン | サーバクラスタ利用時 |
Java プロジェクトの準備
依存関係は orientdb-graphdb としておけばあらかた入ってくる。
build.gradle は以下。
apply plugin: 'java' apply plugin: 'idea' repositories { mavenCentral() } dependencies { compile 'com.orientechnologies:orientdb-graphdb:2.0.4' }
OrientDB設定ファイルの準備
最低限の設定ファイルを以下のように準備する。
名前はなんでもよいが、orientdb-server-config.xml
として設定ファイルを作成。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <orient-server> <network> <protocols> <protocol name="binary" implementation="com.orientechnologies.orient.server.network.protocol.binary.ONetworkProtocolBinary"/> <protocol name="http" implementation="com.orientechnologies.orient.server.network.protocol.http.ONetworkProtocolHttpDb"/> </protocols> <listeners> <listener ip-address="0.0.0.0" port-range="2424-2430" protocol="binary"/> <listener ip-address="0.0.0.0" port-range="2480-2490" protocol="http"/> </listeners> </network> <users> <user name="root" password="root" resources="*"/> </users> <properties> <entry name="log.console.level" value="info"/> <entry name="log.file.level" value="fine"/> <entry name="plugin.dynamic" value="false"/> </properties> </orient-server>
src/main/resources/orientdb-server-config.xml
に配置しておく。
サーバの起動と停止
起動と停止は以下の流れ。
OServer server = OServerMain.create(); server.startup(new File("/path/to/config/orientdb-server-config.xml")); server.activate(); ... server.shutdown();
設定ファイルは InputStream として渡すこともできる。
Document API
MongoDB や CouchDB と同じようにスキーマレスのドキュメントを扱う。
ODatabaseDocumentTx
が入り口となるクラスで、基本的な流れは以下となる。
ODatabaseDocumentTx db = new ODatabaseDocumentTx("memory:foo").create(); ODocument foo = new ODocument(); foo.setClassName("Foo"); foo.field("code", i); foo.save(); db.close();
ODatabaseDocumentTx に渡す接続設定は以下の形式。
connect remote:localhost:{port}/{db} {user} {password}
ここではローカルのインメモリで利用するので memory:foo
で良い。
ストレージ利用ならplocal:/path/to/db
のようにパスを指定。
他項目の説明は以下。
項目 | 説明 |
---|---|
remote | リモート接続の場合はremote 。 ローカル接続の場合は plocal 。 インメモリの場合は memory 。 |
port | バイナリサーバのリスンポート番号を指定。設定ファイル中"2424-2430"に該当 |
db | データベース名を指定。デフォルトは db 。設定ファイルで<entry name="server.database.path" value="db"/> のように指定もできる |
user | DB接続するユーザ名 |
password | DB接続するユーザのパスワード |
Document APIの利用例
では組み込みでOrientDBのサーバ起動して Document APIを利用してみる。
Main.java
package example; import com.orientechnologies.orient.core.config.OGlobalConfiguration; import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx; import com.orientechnologies.orient.core.record.impl.ODocument; import com.orientechnologies.orient.core.sql.OCommandSQL; import com.orientechnologies.orient.server.OServer; import com.orientechnologies.orient.server.OServerMain; import java.util.stream.IntStream; public class Main { private OServer server; public void exec() { ODatabaseDocumentTx db = new ODatabaseDocumentTx("memory:foo").create(); OGlobalConfiguration.USE_WAL.setValue(false);// Write Ahead Log try { long start = System.currentTimeMillis(); final ODocument foo = new ODocument(); System.out.println("start"); IntStream.range(0, 200000).forEach( i -> { foo.reset(); foo.setClassName("Foo"); foo.field("code", i); foo.save(); }); long end = System.currentTimeMillis(); System.out.println(end - start + "ms" + " " + ((end - start) / 200000.) + "ms/レコード"); db.command(new OCommandSQL("TRUNCATE CLASS Foo")).execute(); } finally { db.close(); } } public void shutdown() throws Exception { server.shutdown(); } public void start() throws Exception { server = OServerMain.create() .startup(getClass().getClassLoader().getResourceAsStream("orientdb-server-config.xml")) .activate(); } public static void main(String...args) { try { Main main = new Main(); main.start(); main.op(); main.shutdown(); } catch (Exception e) { e.printStackTrace(); } } }
実行
Main クラス実行すると以下のように出力される。
OrientDB auto-config DISKCACHE=4,323MB (heap=1,820MB os=8,192MB disk=139,579MB) [orientechnologies] INFO Loading configuration from input stream [OServerConfigurationLoaderXml] INFO OrientDB Server v2.0.3 is starting up... [OServer] INFO Databases directory: /・・・/orientdb-example/./databases [OServer] INFO Listening binary connections on 0.0.0.0:2424 (protocol v.28, socket=default) [OServerNetworkListener] INFO Listening http connections on 0.0.0.0:2480 (protocol v.10, socket=default) [OServerNetworkListener] INFO OrientDB Server v2.0.3 is active. [OServer] start 5572ms 0.02786ms/レコード INFO OrientDB Server is shutting down... [OServer] INFO Shutting down listeners: [OServer] INFO - ONetworkProtocolBinary /0.0.0.0:2424: [OServer] INFO - ONetworkProtocolHttpDb /0.0.0.0:2480: [OServer] INFO Shutting down protocols [OServer] INFO Shutting down plugins: [OServerPluginManager] INFO Shutting down databases: [OServer] INFO - closing storage: foo... [Orient] INFO OrientDB Engine shutdown complete [Orient] INFO OrientDB Server shutdown complete [OServer]
1レコード当たり、0.03 ms 程度。
gradle から実行する場合には、build.gradle に以下追加し
apply plugin: 'application' mainClassName = 'example.Main'
コマンドラインから
gradle run
すれば良い。
Graph API
Graph API はblueprintsに従うので Neo4 と同じように扱える。
OrientGraph
が入り口となるクラスで、基本的な流れは以下となる。
OrientGraph graph = new OrientGraph("memory:foo"); try { Vertex luca = graph.addVertex(null); ... graph.commit(); } catch( Exception e ) { graph.rollback(); } finally { graph.shutdown(); }
トランザクションの開始は上記 graph.addVertex(null)
のような graph への操作で暗黙的に開始する。shutdown()
でトランザクションは暗黙的にコミットされる。明示的に commit()
することもできる。
Vertex と Edge の生成
Vertex は OrientGraph.addVertex(Object id)
で生成する。
Vertex v = graph.addVertex(null); System.out.println("Created vertex: " + v.getId());
ID は自動取得される。
Edge は OrientGraph.addEdge(Object id, Vertex outVertex, Vertex inVertex, String label)
で生成する。
Vertex luca = graph.addVertex(null); luca.setProperty("name", "Luca"); Vertex marko = graph.addVertex(null); marko.setProperty("name", "Marko"); Edge lucaKnowsMarko = graph.addEdge(null, luca, marko, "knows"); System.out.println("Created edge: " + lucaKnowsMarko.getId());
Vertex と Edge 取得
それぞれ getVertices()
getEdges()
を使う。
for (Vertex v : graph.getVertices()) { System.out.println(v.getProperty("name")); } for (Edge e : graph.getEdges()) { System.out.println(e.getProperty("age")); }
Vertex と Edge の削除
removeXXX()
で削除する。
graph.removeVertex(luca); graph.removeEdge(lucaKnowsMarko);
属性の操作
属性は以下のように操作する。
vertex2.setProperty("x", 30.0f); vertex2.setProperty("y", ((float) vertex1.getProperty( "y" )) / 2); for (String property : vertex2.getPropertyKeys()) { System.out.println("Property: " + property + "=" + vertex2.getProperty(property)); } vertex1.removeProperty("y");
一括で設定する場合は以下のようにもできる。
vertex.setProperties( "name", "Jill", "age", 33, "city", "Rome", "born", "Victoria, TX" ); Map<String,Object> props = new HashMap<String,Object>(); props.put("name", "Jill"); props.put("age", 33); props.put("city", "Rome"); props.put("born", "Victoria, TX"); vertex.setProperties(props);
Object API
OObjectDatabaseTx が入り口となるクラスで、基本的な流れは以下となる。
OObjectDatabaseTx db = new OObjectDatabaseTx("memory:foo").create(); db.getEntityManager().registerEntityClasses("foo.domain"); try { ... } finally { db.close(); }
Objectデータベースの生成
インメモリの場合は以下のようになる。
OObjectDatabase db1 = new OObjectDatabaseTx("memory:petshop").create();
リモートデータベースへの接続は以下のようになる。
OObjectDatabase db2 = new OObjectDatabaseTx("remote:localhost/petshop").open("admin", "admin");
コネクションプーリングを利用する場合は以下のように OObjectDatabaseTx
を取得する。
OObjectDatabaseTx db= OObjectDatabasePool.global().acquire("remote:localhost/petshop", "admin", "admin");
スキーマレスのObjectDB利用
以下のPOJOがある場合、
public class Person { private String name; private String surname; public Person(){ } public Person(String name){ this.name = name; } public Person(String name, String surname){ this.name = name; this.surname = surname; } // getters and setters }
以下で永続化できる。
OObjectDatabase db = new OObjectDatabaseTx("memory:petshop").create(); db.getEntityManager().registerEntityClass(Person.class); Person p = db.newInstance(Person.class); p.setName("Luca"); p.setSurname("Garulli"); p.setCity(new City("Rome", "Italy")); db.save(p); Person person = db.newInstance(Person.class, "Antoni"); animal.setSurname("Gaudi"); db.save(person); Person person = db.newInstance(Person.class, "Antoni", "Gaudi"); db.save(person); db.close();
newInstance()
の第2引数以降にコンストラクタ引数が渡せる。
以下のフィールドは永続化対象外となる。
- transient の付いたフィールド
- static 指定されたフィールド
- getter/setter が無いフィールド
- 無名クラス型のセット
newInstance()
からではなく、通常のオブジェクトの永続化もできる。
Person p = new Person(); p.setName("Gaudi"); p.setSurname("Madrid"); p = db.save(p);
この場合 save() の戻り値のオブジェクトが データベースとのプロキシとなる。
ObjectAPI によるレコードの照会
cluster から全てのレコードを取得するには以下。
for (Object o : database.browseCluster("CityCars")) System.out.println( ((Car) o).getModel() );
class から全てのレコードを取得するには以下。
for (Animal animal : database.browseClass(Animal.class)) { System.out.println( animal.getName() );
レコード件数の取得は以下。
long cityCars = database.countCluster("CityCar"); long cars = database.countClass("Car");
ObjectAPI による更新と削除
更新は保存時と同じように save を呼べば良い。更新されたフィールドが変更される。
animal.setLocation("Nairobi");
db.save(animal);
削除は以下。
db.delete(animal);
削除時のカスケードは JPA の orphanRemoval = true
と同じ。
public class JavaCascadeDeleteTestClass { @OneToOne(orphanRemoval = true) private JavaSimpleTestClass simpleClass; @ManyToMany(cascade = { CascadeType.REMOVE }) private Map<String, Child> children = new HashMap<String, Child>(); @OneToMany(orphanRemoval = true) private List<Child> list = new ArrayList<Child>(); @OneToMany(orphanRemoval = true) private Set<Child> set = new HashSet<Child>(); ... // getter/setter }
以下のように削除すれば良い。
database.delete(testClass); for (JavaCascadeDeleteTestClass testClass : database.browseClass(JavaCascadeDeleteTestClass.class)) database.delete(testClass);
クエリとコマンド
以下のように OSQLSynchQuery
でクエリ発行できる。
List<Animal> result = db.query( new OSQLSynchQuery<Animal>("select * from Animal where ID = 10 and name like 'G%'"));
コマンドは OCommandSQL
で行う。
int recordsUpdated = db.command( new OCommandSQL("update Animal set sold = false")).execute();

Getting Started with OrientDB (English Edition)
- 作者:Claudio Tesoriero
- 出版社/メーカー: Packt Publishing
- 発売日: 2013/11/22
- メディア: Kindle版

NoSQLプログラミング実践活用技法 (Programmer’s SELECTION)
- 作者:Shashank Tiwari
- 出版社/メーカー: 翔泳社
- 発売日: 2012/05/18
- メディア: 大型本