ラベル NoSQL の投稿を表示しています。 すべての投稿を表示
ラベル NoSQL の投稿を表示しています。 すべての投稿を表示

2012年1月1日日曜日

2012年やりたいこと

昨年後半はいろいろと個人的にバタバタしたため、ブログの更新もほとんどできていませんでした
(NetBeans 7.1 も RC2 まで現在リリースされていますが、ご紹介できていない状態ですし…)
今年は少し余裕ができるのではという感じなので、ブログも含め、以下のことを中心に学習、アウトプットをしていきたいと思っています
(宣言的に書かないと、そのままダラダラと流されそうなので…)

・ NetBeans の機能紹介
・ OrientDB を中心とする GraphDB 関連について
・ ネットワークなど、過去見送ってきた基礎知識に関しての学習記録
・ NetBeans 用プラグインの開発について
・ Scala や Python 、 PHP などについて

とにかく、継続してアウトプットすることを頑張りたいと思います
まずは、今月上旬には 7.1 が正式にリリースされる予定なので、そちらについて紹介できればと思います
(7.1 以降のリリーススケジュールについては、 2012年1月1日現在では不明ですが…)

今年も本ブログを何卒、宜しくお願い致します

2011年4月12日火曜日

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

前回の投稿から半年以上過ぎましたが、OrientDB の紹介3回目です
前の2回は以下の通りです

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

データ間の関連(リレーション)について紹介します
データ間の関連とは2つの異なるレコードを関連付けることで、データの透過的な参照や複雑なデータ構造の表現が可能となります

OrientDB では参照型( Referenced relationships )と組込型( Embedded relationships )という2種類の関連付けをサポートしています
参照型は、フィールドに対象レコードのレコードID(全レコードにてユニークとなるID)を持つことでデータ間の関連付けを行います
そのため、関連付ける各レコードは独立したレコードとして各々参照できる必要があります
対して組込型は、フィールドに直接レコードをそのものを設定するもので、組み込まれたレコードを独立して参照することはできません

また、参照、組込型として関連付けられるデータは 1:1 だけでなく、各々 List 、 Set 、 Map という 1:N 、または N:M の関係を作ることができます
(今回はこの部分の説明の詳細は省略させて頂きます)

それでは実際にデータの登録を行い、どのような構造のレコードが生成されるかを説明したいと思います
今回使用した環境は下記の通りです

・Mac OS X 10.6.7
・Java(TM) SE Runtime Environment (build 1.6.0_24-b07-334-10M3326)
・OrientDB 0.9.25
・NetBeans 7.0 RC2

以降は上記環境にて、サーバの起動、専用クライアント(コンソール)の接続まで完了している前提で進めます
サーバやクライアントの起動方法、クライアントを使用したレコード操作などについては、前々回のエントリを参照ください
また、文中で使われるレコードIDは環境により異なりますので、お使いの環境にあわせて読み替えてください

まず、テストデータを登録するため、下記クエリを実行して Person クラスと Group クラスを作成します
( ">" はプロンプトとなりますので、コピーして実行する際にはご注意ください)
> create class Person
> create class Group
次に Group クラス のデータを登録します
> insert into Group (name) values ('Rebel Alliance')
> insert into Group (name) values ('Galactic Empire')
下記コマンドで Group クラスに2レコード登録されたことが確認できます
> browse class Group
---+--------+--------------------
  #| REC ID |NAME                
---+--------+--------------------
  0|    25:0|Rebel Alliance      
  1|    25:1|Galactic Empire     
---+--------+--------------------
"REC ID" は先の説明のレコードIDを指し、 "Rebel Alliance" は "25:0" 、 "Galactic Empire" は "25:1" のレコードIDを持つこととなります

次に参照型の関連フィールドを持つレコードを作成します
関連付けるレコードは先ほど登録した Group クラスのレコードです
下記クエリを実行して、 レコードを登録します
> insert into Person (name, surname, group) values ('Luke', 'Skywalker', 25:0)
> insert into Person (name, surname, group) values ('Han', 'Solo', 25:0)
> insert into Person (name, group) values ('Chewbacca', 25:0)
> insert into Person (name, surname, group) values ('Leia', 'Organa', 25:0)

> insert into Person (name, group) values ('Darth Sidious', 25:1)
> insert into Person (name, group) values ('Darth Vader', 25:1)
レコードに関連付けを設定する場合は、フィールドに対象のレコードIDを直接記述します
(そのため、事前に関連づけるレコードIDを知っておく必要があります)
上記の場合、 "group" というフィールドにレコードIDを設定しており、これで Person クラスと Group クラスの各レコードが関連付けられることとなります

下記コマンドで Person クラスに6レコード登録されたことが確認できます
> browse class Person
---+--------+--------------------+--------------------+--------------------
  #| REC ID |NAME                |SURNAME             |GROUP               
---+--------+--------------------+--------------------+--------------------
  0|    24:0|Luke                |Skywalker           |25:0                
  1|    24:1|Han                 |Solo                |25:0                
  2|    24:2|Chewbacca           |null                |25:0                
  3|    24:3|Leia                |Organa              |25:0                
  4|    24:4|Darth Sidious       |null                |25:1                
  5|    24:5|Darth Vader         |null                |25:1                
---+--------+--------------------+--------------------+--------------------
関連付けられたレコードに対しては、「フィールド名.対象レコードのフィールド名」の形式で指定することで値を参照することができます
以下は select 文にて group フィールドに関連付けられた、 Group クラスの name フィールドを参照しています
(where 句にある "@rid" はレコードIDを意味するレコード属性になります)
> select name, surname, group.name from Person where @rid = 24:0
---+--------+--------------------+--------------------+--------------------
  #| REC ID |NAME                |SURNAME             |GROUP               
---+--------+--------------------+--------------------+--------------------
  0|   -1:-1|Luke                |Skywalker           |Rebel Alliance      
---+--------+--------------------+--------------------+--------------------
また、他のフィールドと同様に where 句の検索条件としても使用できます
> select from Person where group.name = 'Rebel Alliance'
---+--------+--------------------+--------------------+--------------------
  #| REC ID |NAME                |SURNAME             |GROUP               
---+--------+--------------------+--------------------+--------------------
  0|    24:0|Luke                |Skywalker           |25:0                
  1|    24:1|Han                 |Solo                |25:0                
  2|    24:2|Chewbacca           |null                |25:0                
  3|    24:3|Leia                |Organa              |25:0                
---+--------+--------------------+--------------------+--------------------
Java API を利用する場合、参照型レコードの登録は以下のようになります
(import 文、パッケージ名は省略しますのでご注意下さい)
public class Main {

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

        // 新規レコード(Group)の作成
        ODocument jediOrder = new ODocument(database, "Group");
        jediOrder.field("name", "Jedi Order");
        jediOrder.save();

        // ユニークIDを取得
        ORID jediOrderORID = jediOrder.getIdentity();
        
        // 新規レコード(Rank)の作成
        ODocument master = new ODocument(database, "Rank");
        master.field("name", "Jedi Master");
        master.save();

        // ユニークIDを取得
        ORID masterOrderORID = master.getIdentity();

        ODocument knight = new ODocument(database, "Rank");
        knight.field("name", "Jedi Knight");
        knight.save();

        // ユニークIDを取得
        ORID knightOrderORID = knight.getIdentity();

        ODocument padawan = new ODocument(database, "Rank");
        padawan.field("name", "Padawan");
        padawan.save();

        // ユニークIDを取得
        ORID padawanOrderORID = padawan.getIdentity();

        // 新規レコード(Person)の作成
        ODocument yoda = new ODocument(database, "Person");
        yoda.field("name", "Yoda");
        yoda.field("group", jediOrderORID);
        yoda.field("rank", masterOrderORID);
        yoda.save();
        
        ODocument obiwan = new ODocument(database, "Person");
        obiwan.field("name", "Obi-Wan");
        obiwan.field("surname", "Kenobi");
        obiwan.field("group", jediOrderORID);
        obiwan.field("rank", knightOrderORID);
        obiwan.save();

        ODocument ahsoka = new ODocument(database, "Person");
        ahsoka.field("name", "Ahsoka");
        ahsoka.field("surname", "Tano");
        ahsoka.field("group", jediOrderORID);
        ahsoka.field("rank", padawanOrderORID);
        ahsoka.save();
        
        // 接続の解除
        database.close();
    }
}
上記では Group クラスに1レコード登録、Rank クラスの新規作成と3レコード登録、 Person クラスに3レコード登録しています
参照型の関連付けを行う方法はクエリを使用したケースと同様にフィールドにレコードIDを設定します
Java API にてレコードID( Java API では ORID クラスにて表現されています)を取得するには、ODocument クラスの getIdentity() メソッドを使用します
なお、新規レコードの場合、事前に save() メソッドを呼び出してデータベースに登録が完了していないとレコードIDは取得できませんので、ご注意ください

レコードを取得する場合は下記のようになります
public class Main {

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

        System.out.println("-----レコードIDを指定してレコードを取得-----");
        
        // RID=24:6(Yoda) を取得
        ODocument yoda = new ODocument(database, new ORecordId(24, 6));
        
        // group フィールドを取得
        ODocument yodaGroup = yoda.field("group");
        Object yodaGroupName = yodaGroup == null ? "" : yodaGroup.field("name");
        // rank 1フィールドを取得
        ODocument yodaRank = yoda.field("rank");
        Object yodaRankName = yodaRank == null ? "" : yodaRank.field("name");
        
        // 取得レコードの出力
        System.out.println("name   : " + yoda.field("name"));
        System.out.println("surname: " + yoda.field("surname"));
        System.out.println("group  : " + yodaGroupName);
        System.out.println("rank   : " + yodaRankName);
        System.out.println();

        System.out.println("-----クエリを実行してレコードを取得-----");
        
        // SELECT 文を作成する
        String selectQuery = "select from Person where group.name = 'Jedi Order' ";

        // クエリを実行する
        List<ODocument> people = database.query(new OSQLSynchQuery<ODocument>(selectQuery));

        for (ODocument person : people) {
            // group フィールドを取得
            ODocument group = person.field("group");
            Object groupName = group == null ? "" : group.field("name");
            // rank 1フィールドを取得
            ODocument rank = person.field("rank");
            Object rankName = rank == null ? "" : rank.field("name");

            // 取得レコードの出力
            System.out.println("name   : " + person.field("name"));
            System.out.println("surname: " + person.field("surname"));
            System.out.println("group  : " + groupName);
            System.out.println("rank   : " + rankName);
            System.out.println();
        }

        // 接続の解除
        database.close();
    }
}
上記を実行すると、以下のように値が取得できます
-----レコードIDを指定してレコードを取得-----
name   : Yoda
surname: null
group  : Jedi Order
rank   : Jedi Master

-----クエリを実行してレコードを取得-----
name   : Yoda
surname: null
group  : Jedi Order
rank   : Jedi Master

name   : Obi-Wan
surname: Kenobi
group  : Jedi Order
rank   : Jedi Knight

name   : Ahsoka
surname: Tano
group  : Jedi Order
rank   : Padawan

次に組込型の関連付けですが、現在(2011年4月12日時点)のバージョンではクエリによる組込型のレコードの登録、更新(参照は可能です)は対応しておらず、 Java API でのみとなります

Java API を利用する場合の登録は以下のようになります
public class Main {

    public static void main(String[] args) {
        // admin ユーザでサーバーの demo データベースに接続します
        ODatabaseDocumentTx database = new ODatabaseDocumentTx("remote:localhost/demo").open("admin", "admin");
        
        // 新規レコードを作成
        ODocument lightsaber = new ODocument(database, "Weapon");
        lightsaber.field("name", "Lightsaber");
        lightsaber.field("type", "sword"); 
        
        // RID=24:0(Luke) を取得
        ODocument luke = new ODocument(database, new ORecordId(24, 0));
        luke.field("weapon", lightsaber, OType.EMBEDDED);
        luke.save();
        
        database.close();
    }
}
上記では Weapon クラスのレコードを1件作成し、 Person クラスのレコードの "weapon" フィールドに設定しています
参照型と大きく異なる点は作成した Weapon クラスの save()メソッドを呼び出していない点、取得した Person クラスの "weapon" フィールドに設定する際、第3引数に "OType.EMBEDDED" を設定している点です

レコードの参照方法に関しては、組込型も参照型も差異はありません
>  select from Person where @rid = 24:0                          

---+--------+--------------------+--------------------+--------------------+--------------------
  #| REC ID |NAME                |WEAPON              |SURNAME             |GROUP               
---+--------+--------------------+--------------------+--------------------+--------------------
  0|    24:0|Luke                |-1:-1               |Skywalker           |25:0                
---+--------+--------------------+--------------------+--------------------+--------------------
参照型のフィールド "group" にはレコードIDの値("25:0")が設定されているのに対し、組込型は直接レコードが設定されているため、レコードIDは設定されていません
組込まれたレコードのフィールドも同様の形式で参照可能です
> select name, surname, weapon.name, weapon.type from Person where @rid = 24:0

---+--------+--------------------+--------------------+--------------------+--------------------
  #| REC ID |NAME                |WEAPON              |SURNAME             |WEAPON2             
---+--------+--------------------+--------------------+--------------------+--------------------
  0|   -1:-1|Luke                |Lightsaber          |Skywalker           |sword               
---+--------+--------------------+--------------------+--------------------+--------------------
以上が OrientDB の関連付けの機能の紹介と利用方法になります

次回は、 OrientDB のグラフデータベースとしての機能を紹介したいと思います
(次はあまり期間をあけないようしたいと思います…)

2010年9月23日木曜日

うれしかったので貼ってみた

前回で2回分 OrientDB について紹介するエントリを書いたところ、開発者の Luca に Tweet いただきました


まだまださわりすら書けていないので、これからも頑張って OrientDB の魅力を書いていけたらなと思います
前回分までのエントリは以下になります

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

OrientDB に興味をもたれた方、ぜひダウンロードして使ってみてください

2010年9月17日金曜日

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

今回は OrientDB という オープンソースの NoSQL データベースを紹介致します
※OrientDB は開発が活発なプロジェクトであるため、記載した機能等が将来変更される可能性があります
 (実際、このエントリ書いてる最中にバージョン上がるし、実行ファイル名変わるし…)

OrientDB は今年(2010年)5月に公開された、新しいプロダクトです
(なお、ベースとなった Orient ODBMS ( C++ にて実装) は1999年にリリースされており、これは10年近くの実績があります)
開発者は Luca Garulli というイタリアの方で、 JDO 1.0 、 2.0 のエキスパートメンバーのひとりです
現在のところ Luca 1人で開発していますが、将来的にはコミュニテイとして開発者を増やしたいとのことです
(そのため、 Wiki のドキュメント整備まで手が回らないのか、情報が最新版と一致していない箇所があります)

OrientDB は DBMS の分類では CouchDB や MongoDB と同じ、ドキュメント指向データベースですが、データ間の関連(リレーション)はグラフデータベースのように扱うといった、複数の DBMS の特徴を備えたものとなっています
この他にも OrientDB には以下のような特徴があります

・100% Java にて記述されている
・軽量である(本体のみで約1MB)
・高速である(一般的なコンピュータ(※1)にて200,000件/秒の登録が可能(※2))
・グラフデータベースのスタックとして Tinkerpop を採用
 (Gremlin などの対応プロダクトが利用可能)
・データ操作には、Java API 、HTTP Restful API、 SQL ライクな構文をサポート
・スキーマレス、スキーマフル、複合の複数のスキーマタイプを選択可能
・ACIDトランザクションのサポート
・組込モード、サーバーモードの2つの動作モードをサポート
・ライセンスは Apache License 2.0
※1 … DELL Notebook model XPS M1530 with Intel(r) Core Duo T7700 2.40Ghz, 3 GB RAM and HD 5.400rpm, O.S. MS Windows Vista, JRE 1.6.0_20
※2 … インメモリでの処理時

また、 OrientDB を基盤とした OrientKV というキー・バリューストアのプロダクトがあります
(OrientDB、OrientKV(Key/Value Server) とは別に Orient Object(Object Database) というプロダクトもあるのですが、 OrientDB のコア機能として含まれているようなのでここでの説明は割愛しています)
OrientKV は本体が軽量、データ処理が高速であるという OrientDB の良い部分を引き継ぎ、且つ複数ノードにデータを分散させて格納する、分散キー・バリューストアとしての運用が設定にて簡単に実現できるという特徴があります
OrientKV の詳細に関しては別エントリにてご紹介したいと思います

次に OrientDB のインストールと、実際の動作についてです
以下の説明は下記環境にて行っています
Windows、Linux をご利用の方は、各環境に合わせて読み替えていただければと思います
(Windows 環境では .sh ファイルを .bat ファイルと読み替えるなど)

・Mac OS X 10.6.4
・Java(TM) SE Runtime Environment (build 1.6.0_20-b02-279-10M3065)

OrientDB のインストールはパッケージのダウンロード、及び展開のみで完了します
コチラのリストより最新版(2010年09月17日現在)である "orientdb-0.9.22.zip" をダウンロードし、適当な場所に展開します

展開後、 "config" ディレクトリ内にある "orient-server-config.xml" ファイルを開き、9行目、10行目ほどにあるリスナのポート番号をご使用の環境に合わせ、変更します
(デフォルト値として設定されている、"2424-2430"(9行目)、"2480-2490"(10行目)の範囲内のポート番号が使用可であれば、特に変更は必要ありません)

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<orient-server>
<network>
<protocols>
<protocol implementation="com.orientechnologies.orient.server.network.protocol.binary.ONetworkProtocolBinary" name="binary"/>
<protocol implementation="com.orientechnologies.orient.server.network.protocol.http.ONetworkProtocolHttpDb" name="http"/>
</protocols>
<listeners>
<listener protocol="binary" port-range="2424-2430" ip-address="127.0.0.1"/>
<listener protocol="http" port-range="2480-2490" ip-address="127.0.0.1">
<!-- 〜中略〜 -->
</orient-server>

また、 "bin" ディレクトリ内に移動し、下記ファイルに実行権限を付与します

$ cd ./bin
$ chmod +x ./server.sh ./console.sh

以上でインストール、及び初期設定は完了です

("bin" ディレクトリ内に移動したままの状態で)下記コマンドを実行し、サーバの起動を行ないます
(サーバを停止する場合は Ctrl + C にて停止します)

$ ./server.sh

最後に実際にデータの登録、参照、更新、削除を行ないたいと思います
OrientDB のデータに対しては、 Java API 、REST API 、同梱のクライアントアプリケーションの "Console" 、そして Web ベースのクライアントアプリケーションである "OrientDB Studio" から操作可能となっています
上記の中ではJava API の動作が一番安定していますが、使いやすさから今回は "Console" での操作を紹介します
(Java API での動作は次回紹介したいと思います)
なお、 "OrientDB Studio" はバグや未実装の機能が多く、 orientdb-0.9.22 のバージョンでは実用するには厳しい状態です

("bin" ディレクトリ内に移動したままの状態で)下記コマンドを実行し、"Console" の起動を行ないます
(起動後はプロンプトの入力待ち状態が ">" となります)

$ ./console.sh

起動後、まず "help" と入力します
下記のように各コマンドとその説明が表示されます

> help

AVAILABLE COMMANDS:

* get Return the value of a property
* classes Display all the configured classes
* set Change the value of a property
* delete Delete records from the database
* insert Insert a new record into the database
* connect Connect to a database
* update Update records in the database
* info Display information about current status
* properties Return all the configured properties
* disconnect Disconnect from the current database
* create database Create a new database
* create cluster Create a new cluster in the current database. The cluster can be physical or logical.
* remove cluster Remove a cluster in the current database. The cluster can be physical or logical.
* load record Load a record in memory and set it as the current one
* display record Display current record's attributes
* grant Grant privileges to a role
* revoke Revoke privileges to a role
* create link Create a link from a JOIN
* create class Create a class
* create property Create a property
* select Execute a query against the database and display the results
* script Execute a script against the current database. If the database is remote, then the script will be executed remotely.
* create index Create an index on a property
* create index Create an index on a property
* browse class Browse all the records of a class
* browse cluster Browse all the records of a cluster
* clusters Display all the configured clusters
* dictionary keys Display all the keys in the database dictionary
* dictionary get Loookup for a record using the dictionary. If found set it as the current record
* dictionary put Insert or modify an entry in the database dictionary. The entry is composed by key=String, value=record-id
* dictionary remove Remove the association in the dictionary
* export database Export a database
* compare databases Compare two databases
* import database Import a database into the current one
* export record Export the current record in the requested format
* help Print this help
* exit Close the console

コマンドの最後にある通り、 "exit" コマンドを使用すると、"Console" アプリケーションを終了することができます

次に "connect" コマンドを実行し、データベースに接続します
"connect" コマンドは以下のように入力します

connect <接続モード>:<データベースパス> <ユーザー名> <ユーザーパスワード>
・"接続モード" には "local" と "remote" があり、ローカルデータベースへの接続は "local" 、ローカル、またはリモートにて起動しているサーバーへの接続には "remote" を使用してください
・"データベースパス" はデータベースまでのパスとなります
 接続モードによりパスの指定が異なり、 "local" ではデータベースまでのファイルパス、 "remote" ではサーバーのアドレスとデータベース名となります
・"ユーザー名" 、 "ユーザーパスワード" はデータベースに設定されているユーザー名、パスワードとなります
 データベース作成時、デフォルトで下記ユーザーが作成されます

  ・ユーザー名:admin / パスワード : admin … データベースに対して、書き込み、読み込み権限を持ちます
  ・ユーザー名:writer / パスワード : writer … データベースに対して、書き込み限を持ちます
  ・ユーザー名:reader / パスワード : reader … データベースに対して、読み込み権限を持ちます

今回はユーザーは "admin" 、データベースは、デフォルトで作成されている "demo" データベースを利用します
使用するコマンドは下記のようになります

> connect remote:localhost/demo admin admin

"Connecting to database [remote:localhost/demo] with user 'admin'...OK" と表示され、入力待ち状態となったら接続成功です
接続に失敗する場合は、ポート番号が衝突していないか、確認してみてください

次にデータを登録しますが、その前にまずクラスの作成を行う必要があります
クラスは RDBMS の表と似た概念になり、データ集合のモデルとなるものです
なお、 OrientDB のクラスは、(上記特徴にも書いたとおり)スキーマレス、スキーマフル、両者の混在という設定が可能です
クラスの作成には "create class" コマンドを使います
"create class" コマンドは以下のように入力します

create class <クラス名>
・"クラス名" は作成するクラス名を指定します
 (クラスの識別として大文字小文字は区別されます)

使用するコマンドは下記のようになります

> create class Person

"Class created successfully with id=xx"(xx はユニークな ID、データベース上にあるクラスの ID が表示されます) と表示されれば、クラスの作成は完了です。
ここで、大きなバグがあるのですが、クラスを作成しても即時反映がされません
"exit" コマンドで接続解除をして、 "console.sh" でコンソールを再起動し、 "connect" コマンドで接続しなおしてください
再接続後、"classes" コマンドを実行すると、既存のクラスに加えて、先程作成したクラス名が表示されるのがわかります

> classes
CLASSES:
--------------------+------+------------------------------------------+-----------+
NAME    | ID | CLUSTERS         | ELEMENTS |
--------------------+------+------------------------------------------+-----------+
ORole    |  0| orole         |   3 |
OUser    |  1| ouser         |   3 |
Account    |  2| account         |  1005 |
Company    |  3| company         |   9 |
Profile    |  4| profile         |   9 |
Whiz    |  5| whiz          |  1000 |
Address    |  6| address         |  164 |
City    |  7| city          |  55 |
Country    |  8| country         |  55 |
Animal    |  9| animal         |   0 |
AnimalRace   | 10| animalrace        |   3 |
OGraphVertex  | 11| ographvertex        |  102 |
OGraphEdge   | 12| ographedge        |  101 |
Person    | 13| person         |   0 |
--------------------+------+------------------------------------------+-----------+
TOTAL                  2509 |
----------------------------------------------------------------------------------+

作成したクラスにスキーマを定義することが可能ですが、今回はスキーマレスで使用します

OrientDB ではデータ操作に、 RDBMS のように SQL に似た構文を使用することができます
データの登録には "INSERT" 文を使います

INSERT INTO <クラス名>|cluster:<クラスタ名> (<フィールド名>[,]*) VALUES (<フィールド値>[,]*)
・"クラス名"にはデータを登録するクラスの名前を記述します
・"クラスタ名" にはデータを格納するクラスタ名を記述します
 (クラスタは今回使用しませんので、説明は省略します)
・"フィールド名"をキーに"フィールド値"が登録されます

以下のデータを登録してみます

> insert into Person (name, surname) values ('Marty', 'McFly')

実行後、 "Inserted record Person@19:0{name:Marty,surname:McFly} in X sec(s)."(Xは秒数(環境により異なります)) のように表示されたら登録成功です
登録されたデータを確認する簡単な方法は "browse class" コマンドを使用することです

> browse class Person

---+--------+--------------------+--------------------
#| REC ID |NAME    |SURNAME   
---+--------+--------------------+--------------------
0| 19:0|Marty    |McFly   
---+--------+--------------------+--------------------

また、 SQL のように "SELECT" 文を使用することもできます
("browse class" コマンドと異なり、抽出する条件や並び順などを指定できます)

SELECT FROM <対象> [WHERE <条件>*] [ORDER BY <フィールド名>* [ASC|DESC]*]
・"対象"には検索する"クラス名"、"クラスタ名"、及び"レコードID"が指定可能です
 ("クラスタ名"、"レコードID"については今回使用しませんので、説明は省略します)
・"条件"には、データを抽出する条件を指定します(省略可能です)
・ORDER BY 句を使用した場合、指定した "フィールド名" 順に昇順( "ASC" )、降順( "DESC" )に並べ替えます

先程登録したデータを検索します

> select from Person where name = 'Marty' order by surname

---+--------+--------------------+--------------------
#| REC ID |NAME    |SURNAME   
---+--------+--------------------+--------------------
0| 19:0|Marty    |McFly   
---+--------+--------------------+--------------------

次はデータの変更(更新)を行ないます

update <クラス名>|cluster:<クラスタ名> set [[,] <フィールド名> = <フィールド値>]* [where <条件>]
・"クラス名"にはデータを更新するクラスの名前を記述します
・"クラスタ名" には更新するデータが格納されたクラスタ名を記述します
 (クラスタは今回使用しませんので、説明は省略します)
・"フィールド名"の値を"フィールド値"にて更新します
・"条件"には、更新対象となるデータの条件を指定します(省略可能ですが、対象が全件となります)

登録したデータを更新します

> update Person set name = 'George' where name = 'Marty'

実行後、 "Updated 1 record(s) in X sec(s)." (Xは秒数(環境により異なります))のように表示されたら更新成功です
"browse class" コマンドを使用すると、変更が確認できます

> browse class Person

---+--------+--------------------+--------------------
#| REC ID |NAME    |SURNAME   
---+--------+--------------------+--------------------
0| 19:0|George    |McFly   
---+--------+--------------------+--------------------

最後にデータの削除を行ないます

DELETE FROM <クラス>|cluster:<クラスタ> [WHERE <条件>]
・"クラス名"にはデータを削除するクラスの名前を記述します
・"クラスタ名" には削除するデータが格納されたクラスタ名を記述します
 (クラスタは今回使用しませんので、説明は省略します)
・"条件"には、削除対象となるデータの条件を指定します(省略可能ですが、対象が全件となります)

更新したデータを削除します

> delete from Person where surname = 'McFly'

実行後、 "Delete 1 record(s) in X sec(s)."(Xは秒数(環境により異なります)) のように表示されたら削除成功です
"browse class" コマンドを使用すると、データが存在しないことが確認できます

> browse class Person

以上で、"Console" アプリケーションを使用した OrientDB の操作方法になります
次回は、 Java API を利用した OrientDB の操作方法を紹介したいと思います

2010年4月30日金曜日

組み込み型グラフデータベース HyperGraphDB で遊ぶ #1

ゴールデンウィークなので、業務では触ることはないであろう、グラフデータベースで遊んでみました
グラフデータベースは情報を表す、または格納するのに、ノード、エッジ、プロパティを使います
(Wikipedia より)
このノード、エッジなどの用語は、データベースの名前ともなっているグラフ理論からきています
従来の RDBMS と比較した場合、グラフデータベースはデータ構造が柔軟で、横断的に情報を抽出することに長けているとされています

最近、オープンソースのグラフデータベース neo4j の 1.0 がリリースされたこと、またそれに関する記事(
InfoQ
マイコミ)も掲載されましたので、既にご存知の方、またはいろいろと試されている方も多いかと思います

今回使用するのは上記の neo4j ではないのですが、同じくオープンソースの組み込み型グラフデータベース、 HyperGraphDB です
まず、HyperGraphDB のサイトよりご使用の環境にあわせたパッケージをダウンロードし、適当な場所に解凍してください
(以降の説明では、解凍した場所を $HGDB_ROOT と表記します)
今回は最新(10/04/30 時点)の HyperGraphDB 1.0 を使用し、説明したいと思います

HyperGraphDB は組み込み型データベースなのでインストール作業は不要なのですが、ストレージ機構として Oracle Berkeley DB を使用しているため、ご使用の環境に Berkeley DB がインストールされていない場合は、別途インストールが必要となります
(Mac OS X や Linux の主なディストリビューションでは標準でインストールされているかと思います)
Google 等で検索頂ければ、各環境でのインストールに関する情報は得られると思いますので、ここでは Berkeley DB のインストールは割愛させて頂きます

また、専用のクライアントアプリケーションは(現時点では)ないので、データ操作は直接 Java のコードを記述して行います
以降の説明ではソースコードの記述、ビルドに関する説明には NetBeans 6.9 Beta を使用しています
他の開発環境をお使いの方は適時読み替えて頂ければと思います

次に開発環境( NetBeans )の準備をします
NetBeans 起動後、"Java アプリケーション" の新規プロジェクトを作成します
作成したプロジェクトを右クリックし、表示されたコンテキストメニューより「プロパティ」を選択します


表示されたプロパティーウィンドウの「カテゴリ」から「実行」を選択します
次に「 VM オプション」のテキストボックスに、"-Djava.library.path=$HGDB_ROOT/native" と入力します
(先述の通り、 $HGDB_ROOT は HyperGraphDB の展開先ですので、環境に合わせて読み替えてください)


「了解」ボタンをクリックし、設定を反映します

プロジェクトツリー内の「ライブラリ」を右クリックし、「 Jar / フォルダを追加」を選択します


Jar / フォルダを追加ウィンドウが開くので、"$HGDB_ROOT/hypergraphdb.jar" を選択します


同様に "$HGDB_ROOT/jars/db.jar" を選択してライブラリに追加します
追加した結果のプロジェクトツリーは以下のようになります


開発環境の準備は以上となります

最後に、簡単なデータの登録と検索(問い合わせ)を行います
まず、データの登録用のクラスを新規作成します
パッケージ名、クラス名は任意で構いませんが、以降は説明のため、"hgdb.sample" パッケージ以下に "Insert" クラスを作成したものとします
作成したクラスに対し、以下のようにソースコードを記述します

package hgdb.sample;

import org.hypergraphdb.HyperGraph;

/**
* データ登録用プログラム
*
* @author Junji Takakura
*/
public class Insert {

public static void main(String[] args) {
// ストレージ(Berkeley DB)用ファイルパスを記述
String databaseLocation = "/tmp/hgdb";

HyperGraph graph = null;

try {
// データベースが存在しなければ、作成、存在していたら、オープンします
graph = new HyperGraph(databaseLocation);
// データベースに "吾輩は猫である" という文字列を登録します
graph.add("吾輩は猫である");
} catch (Exception ex){
ex.printStackTrace();
} finally {
if(graph != null) {
// データベースのクローズ
graph.close();
}
}
}

}

記述後、ファイルを実行(Shift + F6)を実行します
実行時にエラーが発生した場合、先述のプロジェクトプロパティの VM オプション、ライブラリの追加が正しく行われているか確認ください
エラーが発生せず、処理の実行が完了すれば、データの登録は完了です

次に、データの登録用のクラスを新規作成します
("hgdb.sample" パッケージ以下に "Select" クラスを作成したものとします)
作成したクラスに対し、以下のようにソースコードを記述します

package hgdb.sample;

import org.hypergraphdb.HGHandle;
import org.hypergraphdb.HGSearchResult;
import org.hypergraphdb.HyperGraph;
import org.hypergraphdb.query.AtomValueCondition;
import org.hypergraphdb.query.ComparisonOperator;
import org.hypergraphdb.query.HGQueryCondition;

/**
*
* @author Junji Takakura
*/
public class Select {

/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// ストレージ(Berkeley DB)用ファイルパスを記述
String databaseLocation = "/tmp/hgdb";

HyperGraph graph = null;

try {
// データベースが存在しなければ、作成、存在していたら、オープンします
graph = new HyperGraph(databaseLocation);
// 検索条件を作成
// 条件は、"吾輩は猫である" という値と等しい(ComparisonOperator.EQ)
// となるデータを取得する
HGQueryCondition condition = new AtomValueCondition(
"吾輩は猫である", ComparisonOperator.EQ);
// 検索実行と結果セットの取得
HGSearchResult<HGHandle> rs = graph.find(condition);

try {
while (rs.hasNext()) {
// 検索結果を HGHandle のインスタンスとして取得します
// HGHandle とは登録したオブジェクトを参照する、
// データベース上で一意となるキーです
// (詳細は次回説明します)
HGHandle current = rs.next();
// 取得したキーにて、データベースよりオブジェクトを取得します
String title = graph.get(current);
// 取得したオブジェクトを標準出力します
// 出力結果は「Found: xxxxxx...」と表示されます
System.out.println("Found: " + title);
}
} finally {
// 結果セットのクローズ
rs.close();
}

} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (graph != null) {
// データベースのクローズ
graph.close();
}
}
}
}

記述後、ファイルを実行(Shift + F6)を実行します
NetBeans の出力ウィンドウに、"Found: 吾輩は猫である" と表示されるかと思います

以上、簡単なデータ登録と検索となります
次回は、ノード、エッジなどのグラフデータベースの概念が HyperGraphDB でどのように実装されているか、また今回使用した登録、検索プログラムの詳細とより複雑なパターンについて紹介できたらと思います

2010年3月24日水曜日

Mac OS X Snow Leopard (10.6.2) に Apache Cassandra をインストールする

先日、Apache Software Foundationのトップレベルプロジェクトになった Apache Cassandra (以下、 Cassandra ) を Mac OS X にインストールする方法を紹介します
(元ネタはコチラになります)
なお、今回のインストール例では簡単に試用することを目的として、ユーザディレクト以下にインストールしています

また、 Cassandra についての詳細は本家サイトWikipedia 等を参照ください

まず、本家サイトより Cassandra 本体をダウンロードします
今回の例では 10/03/14 時点で最新リリースとなる、 apache-cassandra-0.5.1-bin.tar.gz を使用して説明します
(異なるバージョンを使用する場合は適時読み替えてください)

ダウンロード後、ユーザディレクト以下の適当な場所に解凍してください
今回は説明上、 "/Users/Cassandra" ディレクトリ以下にインストールするものとします
また、展開されたディレクトリ、"/Users/Cassandra/apache-cassandra-0.5.1" を $CASSANDRA_HOME と表記します

"$CASSANDRA_HOME/conf/strage-conf.xml" を編集します
"Directories" の項目( "CommitLogDirectory" 、 "DataFileDirectory" 、 ”CalloutLocation” 、 ”StagingFileDirectory” )を以下のように変更します
  <!--
‾ Directories: Specify where Cassandra should store different data on
‾ disk. Keep the data disks and the CommitLog disks separate for best
‾ performance
-->
<CommitLogDirectory>/Users/Cassandra/apache-cassandra-0.5.1/commitlog</CommitLogDirectory>
<DataFileDirectories>
<DataFileDirectory>/Users/Cassandra/apache-cassandra-0.5.1/data</DataFileDirectory>
</DataFileDirectories>
<CalloutLocation>/Users/Cassandra/apache-cassandra-0.5.1/callouts</CalloutLocation>
<StagingFileDirectory>/Users/Cassandra/apache-cassandra-0.5.1/staging</StagingFileDirectory>

次に "$CASSANDRA_HOME/conf/log4j.properties" を編集します
ログ出力場所を以下のように変更します
# Edit the next line to point to your logs directory
log4j.appender.R.File=/Users/Cassandra/apache-cassandra-0.5.1/log/cassandra/system.log


最後に "$CASSANDRA_HOME/bin/cassandra.in.sh" を編集します
"JVM_OPTS" より、 "-Xrunjdwp:transport" の "address"(初期値8888) 、 "-Dcom.sun.management.jmxremote.port"(初期値8080) の項目をご使用の環境で使用していないポートに変更します
(初期値となっているポート番号を使用していない等、特に変更の必要がない場合は編集は不要です)

以上で準備が終わりましたので、 Cassandra を起動します
Terminal.app 等で "$CASSANDRA_HOME/bin" 以下にカレントディレクトリを変更し、以下のコマンドを実行します
cassandra -f


数行起動ログが表示された後、 Cassandra が起動します
"ERROR: transport error 202: bind failed: Address already in use" というエラーメッセージが表示された場合、使用するポートが、すでに別のアプリケーションに使用されている可能性があります
"$CASSANDRA_HOME/bin/cassandra.in.sh" の設定を見直してください

無事起動したら、クライアントからサーバにアクセスします
"$CASSANDRA_HOME/bin" 以下にある "cassandra-cli" コマンドを下記のように実行してください
cassandra-cli -host localhost

実行後、 サーバコンソールが起動しますので、 "show version" コマンドを実行します
下記のようにバージョン情報が表示されます
cassandra> show version
0.5.1


以上で Cassandra のインストールと起動になります
次回はクライアントからデータの追加について説明したいと思います