4.3. いろいろなデータの保存

Groongaは全文検索エンジンを起源として独自のカラムストアを持つに至るわけですが、索引語や文書を保存するだけでなく、数値や文字列、日時や経緯度など、いろいろなデータを保存することができます。本チュートリアルでは、Groongaで保存できるデータの種類、および保存の方法を説明します。

4.3.1. データの種類

Groongaにおいて利用できる基本型は、真偽値、数値、文字列、日時、経緯度の5種類に大別できます。基本型において、数値は整数・浮動小数点数の違い、符号の有無と割り当てるビット数によって細分化できるほか、文字列は長さの上限によって細分化できます。また、経緯度には測地系による分類があります。詳しくは データ型 を参照してください。

拡張型としては、別テーブルを参照するための情報であるテーブル参照を保存することができます。また、基本型もしくはテーブル参照を複数まとめて保存できるように、ベクターカラムをサポートしています。

それでは、本チュートリアルで使用するテーブルを作成しておきましょう。

実行例:

table_create --name ToyBox --flags TABLE_HASH_KEY --key_type ShortText
# [[0, 1337566253.89858, 0.000355720520019531], true]

4.3.2. 真偽値

ブール型は真偽値(true/false)を表現するための型です。ブール型のカラムを作成するには、 column_create コマンドの type 引数に Bool を指定します。ブール型のデフォルト値はfalseです。

以下の例では、ブール型のカラムを作成し、3つのレコードを追加します。3番目のレコードについては、値を省略しているため、デフォルト値が格納されます。

実行例:

column_create --table ToyBox --name is_animal --type Bool
# [[0, 1337566253.89858, 0.000355720520019531], true]
load --table ToyBox
[
{"_key":"Monkey","is_animal":true}
{"_key":"Flower","is_animal":false}
{"_key":"Block"}
]
# [[0, 1337566253.89858, 0.000355720520019531], 3]
select --table ToyBox --output_columns _key,is_animal
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         3
#       ],
#       [
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "is_animal",
#           "Bool"
#         ]
#       ],
#       [
#         "Monkey",
#         true
#       ],
#       [
#         "Flower",
#         false
#       ],
#       [
#         "Block",
#         false
#       ]
#     ]
#   ]
# ]

4.3.3. 数値

数値型は、整数と浮動小数点数に分けることができます。整数は、符号付き整数と符号なし整数に分けることができるだけでなく、割り当てるビット数によっても分けることができます。割り当てるビット数を大きくすると、カラムのサイズは大きくなってしまいますが、表現できる整数の範囲を大きくすることができます。詳しくは データ型 を参照してください。数値型のデフォルト値はいずれも0です。

以下の例では、Int8型のカラムとFloat型のカラムを作成し、既存のレコードを更新します。 load コマンドはweightカラムの値を期待したとおりに更新しています。一方、priceカラムに指定した小数については、小数点以下を切り捨てた値が格納されています。また、表現できる範囲を超える値を格納しようとした2番目のレコードについては、指定した値とは異なる値が格納されています。このように、表現できる範囲を超える値を指定すると、操作後の値は未定義になるので注意してください。

実行例:

column_create --table ToyBox --name price --type Int8
# [[0, 1337566253.89858, 0.000355720520019531], true]
column_create --table ToyBox --name weight --type Float
# [[0, 1337566253.89858, 0.000355720520019531], true]
load --table ToyBox
[
{"_key":"Monkey","price":15.9}
{"_key":"Flower","price":200,"weight":0.13}
{"_key":"Block","weight":25.7}
]
# [[0, 1337566253.89858, 0.000355720520019531], 3]
select --table ToyBox --output_columns _key,price,weight
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         3
#       ],
#       [
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "price",
#           "Int8"
#         ],
#         [
#           "weight",
#           "Float"
#         ]
#       ],
#       [
#         "Monkey",
#         15,
#         0.0
#       ],
#       [
#         "Flower",
#         -56,
#         0.13
#       ],
#       [
#         "Block",
#         0,
#         25.7
#       ]
#     ]
#   ]
# ]

4.3.4. 文字列

文字列型は、長さの上限によって分けることができます。詳しくは データ型 を参照してください。文字列型のデフォルト値は長さ0の文字列です。

以下の例では、 ShortText 型のカラムを作成し、既存のレコードを更新します。3つ目のレコード(キーが "Block" のレコード)は更新していないのでデフォルト値(長さが0の文字列)になります。

実行例:

column_create --table ToyBox --name name --type ShortText
# [[0, 1337566253.89858, 0.000355720520019531], true]
load --table ToyBox
[
{"_key":"Monkey","name":"Grease"}
{"_key":"Flower","name":"Rose"}
]
# [[0, 1337566253.89858, 0.000355720520019531], 2]
select --table ToyBox --output_columns _key,name
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         3
#       ],
#       [
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "name",
#           "ShortText"
#         ]
#       ],
#       [
#         "Monkey",
#         "Grease"
#       ],
#       [
#         "Flower",
#         "Rose"
#       ],
#       [
#         "Block",
#         ""
#       ]
#     ]
#   ]
# ]

4.3.5. 日時

日時を表現するための型はTimeです。内部では1970年1月1日0時0分0秒を基準とする経過時間をマイクロ秒単位で表現します。符号付きの整数を用いるため、1970年以前の日時も表現することができます。内部表現はマイクロ秒単位の整数ですが、 load コマンドおよび select コマンドでは、経過秒数による指定・表示となります。デフォルト値は1970年1月1日0時0分0秒のことを表す0.0です。

注釈

Groonga内部では経過秒数を整数のペアで保持しています。最初の整数で秒を表現し、もう一方でマイクロ秒を表現します。それゆえGroongaでは小数で経過秒数を表示します。整数部が秒数で、小数部はマイクロ秒の値です。

以下の例では、 Time 型のカラムを作成し、既存のレコードを更新します。1つ目のレコード(キーが "Monkey" のレコード)は更新していないのでデフォルト値( 0.0 )になります。

実行例:

column_create --table ToyBox --name time --type Time
# [[0, 1337566253.89858, 0.000355720520019531], true]
load --table ToyBox
[
{"_key":"Flower","time":1234567890.1234569999}
{"_key":"Block","time":-1234567890}
]
# [[0, 1337566253.89858, 0.000355720520019531], 2]
select --table ToyBox --output_columns _key,time
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         3
#       ],
#       [
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "time",
#           "Time"
#         ]
#       ],
#       [
#         "Monkey",
#         0.0
#       ],
#       [
#         "Flower",
#         1234567890.12346
#       ],
#       [
#         "Block",
#         -1234567890.0
#       ]
#     ]
#   ]
# ]

4.3.6. 経緯度

経緯度を表現するための型は、測地系によって分けることができます。詳しくは データ型 を参照してください。経緯度の指定・表示には、以下に示す形式の文字列を使います。

  • "経度のミリ秒表記x緯度のミリ秒表記" (例: "128452975x503157902")

  • "経度の度数表記x緯度の度数表記" (例: "35.6813819x139.7660839")

小数点を含んでいなければミリ秒表記、小数点を含んでいれば度数表記として扱われます。ミリ秒表記と度数表記を混ぜたときの動作は未定義なので注意してください。経度と緯度の区切りとしては、'x' のほかに ',' を使うことができます。経緯度のデフォルト値は "0x0" です。

以下の例では、世界測地系を用いる WGS84GeoPoint 型のカラムを作成し、既存のレコードを更新します。2つ目のレコード(キーが "Flower" のレコード)は更新していないのでデフォルト値( "0x0" )になります。

実行例:

column_create --table ToyBox --name location --type WGS84GeoPoint
# [[0, 1337566253.89858, 0.000355720520019531], true]
load --table ToyBox
[
{"_key":"Monkey","location":"128452975x503157902"}
{"_key":"Block","location":"35.6813819x139.7660839"}
]
# [[0, 1337566253.89858, 0.000355720520019531], 2]
select --table ToyBox --output_columns _key,location
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         3
#       ],
#       [
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "location",
#           "WGS84GeoPoint"
#         ]
#       ],
#       [
#         "Monkey",
#         "128452975x503157902"
#       ],
#       [
#         "Flower",
#         "0x0"
#       ],
#       [
#         "Block",
#         "128452975x503157902"
#       ]
#     ]
#   ]
# ]

4.3.7. テーブル参照

Groongaでは、テーブル参照のカラム、すなわち関連付けたテーブルを参照するカラムを作成できます。より正確には、カラム作成時に参照先となるテーブルとの関連付けをおこない、参照先テーブルにおけるレコードIDを格納しておくことにより、参照先のレコードにアクセスできるようにします。

テーブル参照のカラムがあるときは、 select コマンドの output_columns 引数に 参照元カラム.参照先カラム と指定することにより、参照先カラムの値を取り出すことができます。参照元カラムのみを指定したときは、 参照元カラム名._key と同様の扱いとなり、参照先レコードの主キーが取り出されます。テーブル参照が有効なレコードを指していないときは、 select コマンドは参照先カラムのデフォルト値を取り出すようになっています。

ここでは、 テーブルの作成 で作成した Site テーブルに参照カラムを作成します。作成する参照カラムは link という名前にします。このカラムには Site テーブルのレコード間でのリンク関係を保存します。

実行例:

column_create --table Site --name link --type Site
# [[0, 1337566253.89858, 0.000355720520019531], true]
load --table Site
[
{"_key":"http://example.org/","link":"http://example.net/"}
]
# [[0, 1337566253.89858, 0.000355720520019531], 1]
select --table Site --output_columns _key,title,link._key,link.title --query title:@this
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         1
#       ],
#       [
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "title",
#           "ShortText"
#         ],
#         [
#           "link._key",
#           "ShortText"
#         ],
#         [
#           "link.title",
#           "ShortText"
#         ]
#       ],
#       [
#         "http://example.org/",
#         "This is test record 1!",
#         "http://example.net/",
#         "test record 2."
#       ]
#     ]
#   ]
# ]

テーブル参照のカラムを作成するときは、 column_create コマンドの type 引数に参照先テーブルを指定します。この例では、同じテーブルに含まれる別のレコードを参照させたいので、Siteを指定することになります。次に、 load コマンドで "http://example.org/" から "http://example.net/" へのリンクを登録しています。テーブル参照を作成するときは、IDではなく主キーを指定することに注意してください。最後に、 select コマンドでリンクの内容を確認しています。この例では、 output_columns 引数に link._key と link.title を指定しているので、参照先の主キーとタイトルが表示されています。

4.3.8. ベクターカラム

column_create コマンドでカラムを作成するとき、 flags 引数にCOLUMN_VECTORフラグを指定すると、 type 引数に指定した型の配列を格納するカラムになります。このようなカラムのことを、ベクターカラムと呼びます。ベクターカラムは、各レコードに複数の値を格納できるため、一対多の参照関係を表すのに便利です。

さきほどテーブル参照の例として作成したカラムでは、各サイトに一つのリンクしか保存できませんでした。通常は一つのサイトから多くのサイトにリンクが張られているので、これでは残念な仕様になってしまいます。そこで、ベクターカラムを使って、複数のリンクを保存できるようにしてみましょう。

実行例:

column_create --table Site --name links --flags COLUMN_VECTOR --type Site
# [[0, 1337566253.89858, 0.000355720520019531], true]
load --table Site
[
{"_key":"http://example.org/","links":["http://example.net/","http://example.org/","http://example.com/"]},
]
# [[0, 1337566253.89858, 0.000355720520019531], 1]
select --table Site --output_columns _key,title,links._key,links.title --query title:@this
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         1
#       ],
#       [
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "title",
#           "ShortText"
#         ],
#         [
#           "links._key",
#           "ShortText"
#         ],
#         [
#           "links.title",
#           "ShortText"
#         ]
#       ],
#       [
#         "http://example.org/",
#         "This is test record 1!",
#         [
#           "http://example.net/",
#           "http://example.org/",
#           "http://example.com/"
#         ],
#         [
#           "test record 2.",
#           "This is test record 1!",
#           "test test record three."
#         ]
#       ]
#     ]
#   ]
# ]

新たなカラムにはSiteテーブルに対する参照の配列を格納するので、 type 引数にSiteを指定するとともに、 flags 引数にCOLUMN_VECTORフラグを指定しています。 column_create コマンドの type パラメーターは前の例と同じです。次に、 load コマンドによる更新では、 "http://example.org/" から "http://example.net/" へのリンクに加えて、 "http://example.org/" と "http://example.com/" へのリンクも登録しています。そして、最後に select コマンドでリンクの内容を確認しています。この例では、 output_columns 引数に links._key と links.title を指定しているので、参照先の主キーとタイトルをそれぞれ配列にしたものが表示されています。