前の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 のグラフデータベースとしての機能を紹介したいと思います
(次はあまり期間をあけないようしたいと思います…)
1 件のコメント:
Event though I can understand only the code snippets and the console outputs
(I don't speak Japanese)
I consider this document as excellent orientdb introduction. Thank you.
コメントを投稿