2010年9月22日水曜日

オープンソース NoSQL データベース OrientDB を使ってみる #2

前回に引き続き、 OrientDB の紹介です
今回は Java API を使用したデータの操作について紹介します
OrientDB では使用する API によりドキュメント指向データベース、オブジェクトデータベース、グラフデータベースとしての特性を利用することができます
(実際はドキュメント指向データベースをベースに、各データベースの特性のラップを通して利用するという実装です)
以降の説明では基本となるドキュメント指向データベースとしての操作について説明しています

操作の対象は、今回もサーバーとして起動している OrientDB とします
OrientDB のインストール、設定、起動については下記のエントリを参照ください

オープンソース NoSQL データベース OrientDB を使ってみる #1

使用する環境は以下のとおりです

・Mac OS X 10.6.4
・Java(TM) SE Runtime Environment (build 1.6.0_20-b02-279-10M3065)
・OrientDB 0.9.22
・NetBeans 6.9.1
※以降の説明はお使いの環境に合わせて、適時読み替えてください

まず、 NetBeans にて Java アプリケーションの新規プロジェクトを作成します
プロジェクト名は任意で構いませんが、ここでは説明のため "OrientDBSample" とします
「主クラスを作成」チェックボックスもチェックしていて下さい

プロジェクト作成後、必要なライブラリの追加を行ないます
"OrientDBSample" プロジェクト内の「ライブラリ」フォルダを右クリックし、表示されたコンテキストメニューより「JAR/フォルダを追加...」をクリックします

ファイル選択ダイアログが表示されるので、 OrientDB を展開したフォルダ内の "lib" フォルダにある、 "orientdb-client-0.9.22.jar" 、及び "orientdb-core-0.9.22.jar" を選択し、「選択」ボタンをクリックします
ダイアログが閉じると、「ライブラリ」フォルダ内に上記2つの JAR ファイルが追加されていることが確認できるかと思います

まず、データベースへ接続を行ないます
接続は前回同様 demo データベースを使用します
プロジェクト作成時に自動生成された Main クラスの main メソッド内に以下のようにコードを追加します
(「主クラスを作成」オプションを選択していなかった場合は、 main メソッドをもつ適当なクラスを作成してください)
package orientdbsample;

import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx;

public class Main {
    public static void main(String[] args) {
        // admin ユーザでサーバーの demo データベースに接続します
        ODatabaseDocumentTx database = new ODatabaseDocumentTx("remote:localhost/demo").open("admin", "admin");

        // 接続の解除
        database.close();
    }
}
以降は上記のソースを基本に処理のコードを追加していきます
(import 文、パッケージ名は省略しますのでご注意下さい)

まずは、登録処理を行うコードです
入力後、正常に動作が完了することを確認してください
public class Main {
    public static void main(String[] args) {
        // admin ユーザでサーバーの demo データベースに接続します
        ODatabaseDocumentTx database = new ODatabaseDocumentTx("remote:localhost/demo").open("admin", "admin");
        
        // Rebellion クラスのレコードを作成
        // ※指定したクラスがデータベースに存在しない場合、自動的に作成してくれます
        ODocument document = new ODocument(database, "Rebellion");
        document.field("name", "Luke");
        document.field("surname", "Skywalker");
        document.save();

        // メソッドチェーンを利用して、 Rebellion クラスのレコードを作成
        new ODocument(database, "Rebellion").field("name", "Han").field("surname", "Solo").save();

        // 接続の解除
        database.close();
    }
}
ORientDB ではドキュメントは ODocument クラスを使用して表します
上記例では、 "Rebellion" クラスのドキュメントを作成しています
"Console" アプリケーションを使用した際には事前にクラスの作成が必要でしたが、 Java API を利用する際にはクラスが存在しない場合は自動的に作成してくれます
フィールドメソッドを使用し、指定したフィールド名にフィールド値を設定します
クラスに指定したフィールドが存在しない場合、新たに追加されます
フィールド値に指定可能な型は以下のようになっています

・文字列型 (java.lang.String)
・ Byte 型 (java.lang.Byte または byte)
・ Short 型 (java.lang.Short または short)
・ Integer 型 (java.lang.Integer または int)
・ Long 型 (java.lang.Long または long)
・ Float 型 (java.lang.Float または float)
・ Double 型 (java.lang.Double または double)
・ Boolean 型 (java.lang.Boolean または boolean)
・日付型 (java.util.Date)
・バイナリ (byte[])
・リスト型 (java.util.Set)
・セット型 (java.util.Set)
・マップ型 (java.util.Map)

上記に加えて、レコード間の関連を表す Link とそれに関係する型が OrientDB にてサポートされている型となります
( Link に関しては別エントリにて説明したいと思います)
例ではシンプルに文字列のみをフィールド値に設定しています
フィールドに値を設定した後、 save() メソッドでデータベースへの登録を行ないます

また、OrientDB ではデータ操作に対して( "Console" アプリケーションと同様に) SQLライクなクエリ(以降は SQL と記述します)を使用することができます
Java API を利用した SQL の実行は OSQLQuery クラスのサブクラス(下記例では OCommandSQL クラス)を使用します
public class Main {
    public static void main(String[] args) {
        // admin ユーザでサーバーの demo データベースに接続します
        ODatabaseDocumentTx database = new ODatabaseDocumentTx("remote:localhost/demo").open("admin", "admin");
        
        // INSERT 文を作成する
        String insertQuery = "insert into Rebellion (name) values ('Chewbacca')";

        // クエリを実行します
        database.command(new OCommandSQL(insertQuery)).execute();

        // 接続の解除
        database.close();
    }
}
次に browseClass メソッドを使用して、先ほど登録した Rebellion クラスの全レコードを表示します
("Console" アプリケーションの "browseClass" コマンドと同様の結果となります)
取得できたレコードの getIdentity() メソッドを呼びだすと、データベースにてユニークなキーとなる、レコード IDが取得できます
public class Main {
    public static void main(String[] args) {
        // admin ユーザでサーバーの demo データベースに接続します
        ODatabaseDocumentTx database = new ODatabaseDocumentTx("remote:localhost/demo").open("admin", "admin");
        
        // Rebellion クラスのレコードのリストを取得
        Iterable<ODocument> documents = database.browseClass("Rebellion");

        // レコードのリストから各レコードを取得します
        for (ODocument person : documents) {
            // レコードの各フィールドを取得
            // レコード ID を取得
            System.out.println("Rec ID : " + person.getIdentity());
            System.out.println("Name   : " + person.field("name"));
            System.out.println("Surname: " + person.field("surname"));
        }

        // 接続の解除
        database.close();
    }
}

実行後、以下のように出力されるかと思います
Rec ID : 19:0
Name : Luke
Surname: Skywalker
Rec ID : 19:1
Name : Han
Surname: Solo
Name : Chewbacca
Surname: null

クラスのレコード件数を取得するには countClass() メソッドを使用します
public class Main {
    public static void main(String[] args) {
        // admin ユーザでサーバーの demo データベースに接続します
        ODatabaseDocumentTx database = new ODatabaseDocumentTx("remote:localhost/demo").open("admin", "admin");
        
        // Rebellion クラスのレコード件数を取得します
        long count = database.countClass("Rebellion");

        System.out.println("Count: " + count);

        // 接続の解除
        database.close();
    }
}
また、個別のレコードを抽出するにはクエリを使用します
OrientDB では先の SQL とは別に Native クエリを使用することができますが、現在 Native クエリは local データベースに接続した場合のみ使用可能という制限があります
今回は remote データベースを前提としていますので、 Native クエリに関しては説明を省略します
Java API を利用したレコード抽出には OSQLQuery クラスのサブクラス(下記例では OSQLSynchQuery クラス)を使用します
public class Main {
    public static void main(String[] args) {
        // admin ユーザでサーバーの demo データベースに接続します
        ODatabaseDocumentTx database = new ODatabaseDocumentTx("remote:localhost/demo").open("admin", "admin");

        // クエリ文字列を作成する
        // name フィールドのフィールド値が "L" で始まるもののみ抽出する
        String query = "select from Rebellion where name like 'L%' ";

        // クエリを実行し、結果のリストを取得します
        List<ODocument> documents = database.query(new OSQLSynchQuery<ODocument>(query));

        // レコードのリストから各レコードを取得します
        for (ODocument person : documents) {
            // レコードの各フィールドを取得
            // レコード ID を取得
            System.out.println("Rec ID : " + person.getIdentity());
            System.out.println("Name   : " + person.field("name"));
            System.out.println("Surname: " + person.field("surname"));
        }

        // 接続の解除
        database.close();
    }
}
実行後、以下のように出力されるかと思います

Rec ID : 19:0
Name : Luke
Surname: Skywalker

次にレコードの更新を行ないます
対象となるレコードを抽出し、値を更新後、 save() メソッドを実行して反映します
対象レコード抽出には "@rid" という特別なフィールド(属性値) とレコードIDを使用しています
また、INSERT 文と同様に command() メソッドと OCommandSQL クラスを使用して UPDATE 文を実行することができます
public class Main {
    public static void main(String[] args) {
        // admin ユーザでサーバーの demo データベースに接続します
        ODatabaseDocumentTx database = new ODatabaseDocumentTx("remote:localhost/demo").open("admin", "admin");

        ODocument person = null;

        // SELECT 文を作成する
        String selectQuery = "select from Rebellion where @rid = 19:0";

        // クエリを実行し、その結果のリストを取得します
        person = ((List<ODocument>) database.query(new OSQLSynchQuery<ODocument>(selectQuery))).get(0);
        // レコードの各フィールドを取得
        System.out.println("Rec ID : " + person.getIdentity());
        System.out.println("Name   : " + person.field("name"));
        System.out.println("Surname: " + person.field("surname"));
        System.out.println("----------");

        // "name" フィールドのフィールド値を "" 更新する
        person.field("name", "Ben");
        person.save();

        // クエリを実行し、その結果のリストを取得します
        person = ((List<ODocument>) database.query(new OSQLSynchQuery<ODocument>(selectQuery))).get(0);
        // レコードの各フィールドを取得
        System.out.println("Rec ID : " + person.getIdentity());
        System.out.println("Name   : " + person.field("name"));
        System.out.println("Surname: " + person.field("surname"));
        System.out.println("----------");

        // UPDATE 文を作成する
        String updateQuery = "update Rebellion set name = 'Anakin' where @rid = 19:0";

        // クエリを実行します
        database.command(new OCommandSQL(updateQuery)).execute();

        // クエリを実行し、その結果のリストを取得します
        person = ((List<ODocument>) database.query(new OSQLSynchQuery<ODocument>(selectQuery))).get(0);
        // レコードの各フィールドを取得
        System.out.println("Rec ID : " + person.getIdentity());
        System.out.println("Name   : " + person.field("name"));
        System.out.println("Surname: " + person.field("surname"));
        System.out.println("----------");

        // 接続の解除
        database.close();
    }
}
実行後、以下のように出力されるかと思います

Rec ID : 19:0
Name : Luke
Surname: Skywalker
----------
Rec ID : 19:0
Name : Ben
Surname: Skywalker
----------
Rec ID : 19:0
Name : Anakin
Surname: Skywalker
----------

最後にレコードの削除を行ないます
対象となるレコードを抽出し、 delete() メソッドを実行して削除します
また、 command() メソッドと OCommandSQL クラスを使用して、 DELETE 文を実行することも可能です
public class Main {
    public static void main(String[] args) {
        // admin ユーザでサーバーの demo データベースに接続します
        ODatabaseDocumentTx database = new ODatabaseDocumentTx("remote:localhost/demo").open("admin", "admin");
        
        // SELECT 文を作成する
        String selectQuery = "select from Rebellion where @rid = 19:0 ";

        // レコードのリストから各レコードを取得します
        for (ODocument document : database.browseClass("Rebellion")) {
            // レコードの各フィールドを取得
            System.out.println("Rec ID : " + document.getIdentity());
            System.out.println("Name   : " + document.field("name"));
            System.out.println("Surname: " + document.field("surname"));
        }

        System.out.println("----------");

        // クエリを実行し、その結果を取得します
        ODocument person = ((List<ODocument>) database.query(new OSQLSynchQuery<ODocument>(selectQuery))).get(0);
        // 取得したレコードの delete() メソッドを実行し、レコードを削除
        person.delete();

        // DELETE 文を作成する(全件削除)
        String deleteQuery = "delete from Rebellion";

        // クエリを実行します
        database.command(new OCommandSQL(deleteQuery)).execute();

        // Rebellion クラスの件数取得(レコード有無判定)
        if(database.countClass("Rebellion") > 0) {
            // レコードのリストから各レコードを取得します
            for (ODocument document : database.browseClass("Rebellion")) {
                // レコードの各フィールドを取得
                System.out.println("Rec ID : " + document.getIdentity());
                System.out.println("Name   : " + document.field("name"));
                System.out.println("Surname: " + document.field("surname"));
            }
        } else {
            System.out.println("Rebellion クラスにはレコードは存在しません");
        }

        // 接続の解除
        database.close();
    }
}
実行後、以下のように出力されるかと思います

Rec ID : 19:0
Name : Anakin
Surname: Skywalker
Rec ID : 19:1
Name : Han
Surname: Solo
Rec ID : 19:2
Name : Chewbacca
Surname: null
----------
Rebellion クラスにはレコードは存在しません

以上で、Java API を利用した OrientDB の操作方法になります
今回説明はしませんでしたが、 OrientDB にはトランザクションも利用できます
しかし、最新リリース版として使用している 0.9.22 ではバグがあり、正しく利用できないという状態です
開発版ではこの問題は修正されているので、次回リリース版である 0.9.23 (10月中旬リリース予定)では問題なく利用出来るかと思います

次回はデータ間の関連(リレーション)について紹介したいと思います

0 件のコメント: