Image
Top
Navigation

チュートリアル16 : JOINじゃなくてLINKを使う(centos)

チュートリアル15 : グラフデータベースで遊ぶ(centos)に続きます。

LINKって何?

ここで、レコード間のリレーションを表現する方法としてのリンク(LINK)を紹介します。これは、前掲したグラフデータベースのEdgeではなく、ドキュメントモデルでも利用できる機能です。
また、リレーショナルデータベースからOrientDBに移行する際にもとても役に立つ機能です。通常、NoSQLでは、リレーショナルDBのJOINは利用できません。その場合、ドキュメントの中にドキュメントを埋め込んだりする非正規的な手法を使うことになります。
しかし、OrientDBではこのリンク(LINK)機能によって、JOINよりも高速に、リレーションを表現できます。

ここで、いかにもリレーショナルデータベース的な、Eコマース風のクラスを3つ定義してみましょう。

ER図

まず、Customer(顧客)クラスとOrders(注文)クラスでリンクの作成や利用の方法を試してみます。

Customer(顧客)クラス

プロパティ 説明
id 顧客ID Integer
cname 顧客名 String
region 地域 String
vip VIP Boolean

クラス定義:

create class Customer
create property Customer.id       Integer
create property Customer.cname    String
create property Customer.region   String
create property Customer.vip      Boolean

データ投入:

insert into Customer (id, cname, region, vip) values (1, 'yamada', 'tokyo', true );
insert into Customer (id, cname, region, vip) values (2, 'suzuki', 'tokyo', false);
insert into Customer (id, cname, region, vip) values (3, 'satoh' , 'chiba', fales);

その結果:


select from Customer
----+-----+----+------+------+-----
#   |@RID |id  |cname |region|vip
----+-----+----+------+------+-----
0   |#12:0|1   |yamada|tokyo |true
1   |#12:1|2   |suzuki|tokyo |false
2   |#12:2|3   |satoh |chiba |null
----+-----+----+------+------+-----

Orders(注文)クラス

プロパティ 説明
id 注文ID Integer
customer_id 顧客ID Integer
order_date 注文日 Datetime

クラス定義:

create class Orders
create property Orders.id            Integer
create property Orders.customer_id   Integer
create property Orders.order_date    Datetime

データ投入:

insert into Orders (id, customer_id, order_date) values (11, 1, '2014-09-01' );
insert into Orders (id, customer_id, order_date) values (12, 1, '2014-08-01' );
insert into Orders (id, customer_id, order_date) values (13, 2, '2014-07-01' );

その結果:


select from Orders
----+-----+----+-----------+-------------------
#   |@RID |id  |customer_id|order_date
----+-----+----+-----------+-------------------
0   |#13:0|11  |1          |2014-09-01 00:00:00
1   |#13:1|12  |1          |2014-08-01 00:00:00
2   |#13:2|13  |2          |2014-07-01 00:00:00
----+-----+----+-----------+-------------------

Customer(顧客)=> Orders(注文)の1対Nのリレーションを、リンク(LINK)によって表現するにはLink型のプロパティを定義します。
他のデータ型ののリファレンスはTYPESを参照して下さい。

LINKによるリレーションは2つに分類できます。

参照型リレーション(Referenced relationships)

リンク先の対象オブジェクトへのダイレクトリンク(レコードID)を格納します。

1対1 N対1の参照型リレーション

ER図
たとえば、上記のOrders(注文)=>Customer(顧客)へのリレーションです。リンク元のオブジェクトに、リンク先のオブジェクトのレコードIDを一つだけもちます。

1対N N対Mの参照型リレーション

ER図

たとえば、上記のCustomer(顧客)=> Orders(注文)へのリレーションです。リンク元のオブジェクトに、リンク先のオブジェクトのレコードIDのコレクションをもちます。コレクションの持ち方には、LINKLIST・LINKSET・LINKMAPの3種類があります。

埋込型リレーション(Embedded relationship)

埋込型リレーションは、レコード中にレコードを埋めこむもので、参照型よりも強いリレーションです。オブジェクト指向でいうコンポジションと同じような概念です。埋めこまれたレコードにレコードIDはありません。そのため直接参照できません。コンテナとなるレコードを通してだけアクセスできます。コンテナとなるレコードが削除された場合は、埋めこまれたレコードも削除されます。

1対1 N対1の埋込型リレーション

ER図
例えば、Customer(顧客)にかならず一個のAddress(住所)を埋め込むような場合に利用します。リンク元のオブジェクトに、リンク先のオブジェクトのレコード自体を一つだけ埋め込みます。

1対N N対Mの埋込型リレーション

ER図
リンク元のオブジェクトに、複数のオブジェクトのレコード自体を複数埋め込みます。コレクションの持ち方には、EMBEDDEDLIST・EMBEDDEDSET・EMBEDDEDMAPの3種類があります。

リンク用のプロパティには以下の型が利用できます。

参照型 埋込型 説明
Link 1件だけ。
Link list ソートされたリンクのリスト。重複可
Link set 未ソートのリンクのセット。重複不可。
Link map ソートされた文字列をキーにしたリンクのマップ。
Embedded 1件だけ。
Embedded list ソートされたレコードのリスト。重複可
Embedded set 未ソートのレコードのセット。重複不可。
Embedded map ソートされた文字列をキーにしたレコードのマップ。重複不可。

参照型のリンクを使ってみる

create property Orders.to_customer     link

実行結果



orientdb {doc-test1}> create property Orders.to_customer     link

Property created successfully with id=4

クラスの情報を見てみます


orientdb {doc-test1}> info class orders

Class................: Orders
Default cluster......: orders (id=13)
Supported cluster ids: [13]
Cluster selection....: round-robin

PROPERTIES
-------------------------------+-------------+-------------------------------+-----------+----------+----------+-----------+-----------+----------+
 NAME                          | TYPE        | LINKED TYPE/CLASS             | MANDATORY | READONLY | NOT NULL |    MIN    |    MAX    | COLLATE  |
-------------------------------+-------------+-------------------------------+-----------+----------+----------+-----------+-----------+----------+
 id                            | INTEGER     | null                          | false     | false    | false    |           |           | default  |
 to_customer                   | LINK        | null                          | false     | false    | false    |           |           | default  |
 order_date                    | DATETIME    | null                          | false     | false    | false    |           |           | default  |
 customer_id                   | INTEGER     | null                          | false     | false    | false    |           |           | default  |
-------------------------------+-------------+-------------------------------+-----------+----------+----------+-----------+-----------+----------+

orientdb {doc-test1}> select * from orders

----+-----+----+-----------+-------------------+-----------
#   |@RID |id  |customer_id|order_date         |to_customer
----+-----+----+-----------+-------------------+-----------
0   |#13:0|11  |1          |2014-09-01 00:00:00|null
1   |#13:1|12  |1          |2014-08-01 00:00:00|null
2   |#13:2|13  |2          |2014-07-01 00:00:00|null
----+-----+----+-----------+-------------------+-----------

Orders(注文)クラスに、to_customerというプロパティが増えていてNULLになっています。

このプロパティに、リンク先のレコードIDをセットしてアップデートしてみましょう。


orientdb {doc-test1}> update orders set to_customer = #12:0 where @rid in [#13:0,#13:1]

Updated record(s) '2' in 0.004000 sec(s).

orientdb {doc-test1}> update orders set to_customer = #12:1 where @rid in [#13:2]

Updated record(s) '1' in 0.003000 sec(s).

orientdb {doc-test1}> select from orders

----+-----+----+-----------+-------------------+-----------
#   |@RID |id  |customer_id|order_date         |to_customer
----+-----+----+-----------+-------------------+-----------
0   |#13:0|11  |1          |2014-09-01 00:00:00|#12:0
1   |#13:1|12  |1          |2014-08-01 00:00:00|#12:0
2   |#13:2|13  |2          |2014-07-01 00:00:00|#12:1
----+-----+----+-----------+-------------------+-----------

3 item(s) found. Query executed in 0.003 sec(s).
orientdb {doc-test1}> load recor0:0

!Unrecognized command: 'load recor0:0'
orientdb {doc-test1}> load record #13:0

--------------------------------------------------
ODocument - Class: Orders   id: #13:0   v.5
--------------------------------------------------
                  id : 11
         customer_id : 1
          order_date : Mon Sep 01 00:00:00 JST 2014
         to_customer : Customer#12:0{id:1,cname:yamada,region:tokyo,vip:true} v1

OK

では、Orders(注文)クラスからCustomer(顧客)クラスの情報を取得するのはどうするのでしょうか?

こんな風に、’to_customer.’をつけることで参照が可能になります。


orientdb {doc-test1}> select id,customer_id,to_customer.id as cid,to_customer.cname as cname from orders

----+-----+----+-----------+----+------
#   |@RID |id  |customer_id|cid |cname
----+-----+----+-----------+----+------
0   |#-2:1|11  |1          |1   |yamada
1   |#-2:2|12  |1          |1   |yamada
2   |#-2:3|13  |2          |2   |suzuki
----+-----+----+-----------+----+------

3 item(s) found. Query executed in 0.008 sec(s).

逆に、Customer(顧客)クラスからOrders(注文)クラスへの1対Nのリンクを張ってみましょう。今度はLink set型を使います。

create property Customer.to_orders     linkset

実行結果


orientdb {doc-test1}> create property Customer.to_orders     linkset

Property created successfully with id=5

orientdb {doc-test1}> info class customer

Class................: Customer
Default cluster......: customer (id=12)
Supported cluster ids: [12]
Cluster selection....: round-robin

PROPERTIES
-------------------------------+-------------+-------------------------------+-----------+----------+----------+-----------+-----------+----------+
 NAME                          | TYPE        | LINKED TYPE/CLASS             | MANDATORY | READONLY | NOT NULL |    MIN    |    MAX    | COLLATE  |
-------------------------------+-------------+-------------------------------+-----------+----------+----------+-----------+-----------+----------+
 region                        | STRING      | null                          | false     | false    | false    |           |           | default  |
 id                            | INTEGER     | null                          | false     | false    | false    |           |           | default  |
 vip                           | BOOLEAN     | null                          | false     | false    | false    |           |           | default  |
 to_orders                     | LINKSET     | null                          | false     | false    | false    |           |           | default  |
 cname                         | STRING      | null                          | false     | false    | false    |           |           | default  |
-------------------------------+-------------+-------------------------------+-----------+----------+----------+-----------+-----------+----------+

コレクションに値をセットするのはUPDATEでADDを使います。


orientdb {doc-test1}> UPDATE Customer ADD to_orders = #13:0 where @rid in #12:0

Updated record(s) '1' in 0.006000 sec(s).

orientdb {doc-test1}> UPDATE Customer ADD to_orders = #13:1 where @rid in #12:0

Updated record(s) '1' in 0.007000 sec(s).

orientdb {doc-test1}> UPDATE Customer ADD to_orders = #13:2 where @rid in #12:1

Updated record(s) '1' in 0.004000 sec(s).

結果を見てみましょう。


orientdb {doc-test1}> select from customer

----+-----+---------+----+------+------+-----
#   |@RID |to_orders|id  |cname |region|vip
----+-----+---------+----+------+------+-----
0   |#12:0|[2]      |1   |yamada|tokyo |true
1   |#12:1|[1]      |2   |suzuki|tokyo |false
2   |#12:2|null     |3   |satoh |chiba |null
----+-----+---------+----+------+------+-----

コマンドラインだとlinksetだと数が表示されるだけですね。

to_ordersのプロパティには、Orders(注文)クラスへのリンクの件数が表示されました。
正しくリンクされているんでしょうか?それにはexpand()関数が使えます。


orientdb {doc-test1}>  select expand(to_orders)  from Customer where @rid in [#12:0]

----+-----+----+-----------+-------------------+-----------
#   |@RID |id  |customer_id|order_date         |to_customer
----+-----+----+-----------+-------------------+-----------
0   |#13:0|11  |1          |2014-09-01 00:00:00|#12:0
1   |#13:1|12  |1          |2014-08-01 00:00:00|#12:0
----+-----+----+-----------+-------------------+-----------

2 item(s) found. Query executed in 0.003 sec(s).

リンクされている、Orders(注文)クラスのレコードが表示されました。

Details(明細)クラス

プロパティ 説明
id 明細ID Integer
order_id 注文ID Integer
item 商品 String
price 単価 Integer
qty 数量 Integer

クラス定義:

create class Details
create property Details.id        Integer
create property Details.order_id  Integer
create property Details.item      String
create property Details.price     Integer
create property Details.qty       Integer

データ投入:

insert into Details (id, order_id, item, price, qty) values (111, 11, 'AAAA', 100, 2);
insert into Details (id, order_id, item, price, qty) values (112, 11, 'BBBB', 200, 1);
insert into Details (id, order_id, item, price, qty) values (121, 12, 'AAAA', 100, 1);
insert into Details (id, order_id, item, price, qty) values (122, 12, 'BBBB', 200, 1);
insert into Details (id, order_id, item, price, qty) values (123, 12, 'CCCC', 300, 1);
insert into Details (id, order_id, item, price, qty) values (131, 13, 'AAAA', 100, 3);
insert into Details (id, order_id, item, price, qty) values (132, 13, 'BBBB', 200, 1);

その結果:


select from Details
----+-----+----+--------+----+-----+----
#   |@RID |id  |order_id|item|price|qty
----+-----+----+--------+----+-----+----
0   |#14:0|111 |11      |AAAA|100  |2
1   |#14:1|112 |11      |BBBB|200  |1
2   |#14:2|121 |12      |AAAA|100  |1
3   |#14:3|122 |12      |BBBB|200  |1
4   |#14:4|123 |12      |CCCC|300  |1
5   |#14:5|131 |13      |AAAA|100  |3
6   |#14:6|132 |13      |BBBB|200  |1
----+-----+----+--------+----+-----+----

Orders(注文)クラスからDetails(明細)クラスへのリンクを張ってみましょう。

create property Orders.to_details     linkset

データをセットします。


update Orders set to_details = [#14:0,#14:1]       where @rid in [#13:0]
update Orders set to_details = [#14:2,#14:3,#14:4] where @rid in [#13:1]
update Orders set to_details = [#14:5,#14:6]       where @rid in [#13:2]

結果はどうでしょう。


orientdb {doc-test1}> select expand(to_details)  from Orders where @rid in [#13:0]

----+-----+----+--------+----+-----+----
#   |@RID |id  |order_id|item|price|qty
----+-----+----+--------+----+-----+----
0   |#14:0|111 |11      |AAAA|100  |2
1   |#14:1|112 |11      |BBBB|200  |1
----+-----+----+--------+----+-----+----

大丈夫ですね。

リンク機能をざっと使ってみました。埋込型のリンクはコマンドラインでは表現が難しいのでまた今度。