4.6. タグ検索・参照関係の逆引き

Groongaはカラム値として他のテーブルへの参照の配列を持つことができます。実は、テーブルへの参照の配列データを用いることによって、いわゆるタグ検索を行うことが可能となります。

タグ検索はGroongaの転置インデックスというデータ構造を用いて高速に行われます。

4.6.2. 参照関係の逆引き

Groongaはテーブル間の参照関係の逆引きを高速に行うためのインデックスを付与することができます。タグ検索は、その1例にすぎません。

例えば、ソーシャルネットワーキングサイトにおける友人関係を逆引き検索することができます。

以下の例では、ユーザー情報を格納するUserテーブルを作成し、ユーザー名を格納するusernameカラム、ユーザーの友人一覧を配列で格納するfriendsカラムとそのインデックスのindex_friendsカラムを追加しています。

実行例:

table_create --name User --flags TABLE_HASH_KEY --key_type ShortText
# [[0, 1337566253.89858, 0.000355720520019531], true]
column_create --table User --name username --flags COLUMN_SCALAR --type ShortText
# [[0, 1337566253.89858, 0.000355720520019531], true]
column_create --table User --name friends --flags COLUMN_VECTOR --type User
# [[0, 1337566253.89858, 0.000355720520019531], true]
column_create --table User --name index_friends --flags COLUMN_INDEX --type User --source friends
# [[0, 1337566253.89858, 0.000355720520019531], true]
load --table User
[
{"_key":"ken","username":"健作","friends":["taro","jiro","tomo","moritapo"]}
{"_key":"moritapo","username":"森田","friends":["ken","tomo"]}
{"_key":"taro","username":"ぐるんが太郎","friends":["jiro","tomo"]}
{"_key":"jiro","username":"ぐるんが次郎","friends":["taro","tomo"]}
{"_key":"tomo","username":"トモちゃん","friends":["ken","hana"]}
{"_key":"hana","username":"花子","friends":["ken","taro","jiro","moritapo","tomo"]}
]
# [[0, 1337566253.89858, 0.000355720520019531], 6]

指定したユーザーを友人リストに入れているユーザーの一覧を表示してみましょう。

実行例:

select --table User --query friends:@tomo --output_columns _key,username
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         5
#       ],
#       [
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "username",
#           "ShortText"
#         ]
#       ],
#       [
#         "ken",
#         "健作"
#       ],
#       [
#         "taro",
#         "ぐるんが太郎"
#       ],
#       [
#         "jiro",
#         "ぐるんが次郎"
#       ],
#       [
#         "moritapo",
#         "森田"
#       ],
#       [
#         "hana",
#         "花子"
#       ]
#     ]
#   ]
# ]
select --table User --query friends:@jiro --output_columns _key,username
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         3
#       ],
#       [
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "username",
#           "ShortText"
#         ]
#       ],
#       [
#         "ken",
#         "健作"
#       ],
#       [
#         "taro",
#         "ぐるんが太郎"
#       ],
#       [
#         "hana",
#         "花子"
#       ]
#     ]
#   ]
# ]

さらに、ドリルダウンを使って、友人リストに入っている数の一覧を表示してみましょう。

実行例:

select --table User --limit 0 --drilldown friends
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         6
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "friends",
#           "User"
#         ],
#         [
#           "index_friends",
#           "UInt32"
#         ],
#         [
#           "username",
#           "ShortText"
#         ]
#       ]
#     ],
#     [
#       [
#         6
#       ],
#       [
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "_nsubrecs",
#           "Int32"
#         ]
#       ],
#       [
#         "taro",
#         3
#       ],
#       [
#         "jiro",
#         3
#       ],
#       [
#         "tomo",
#         5
#       ],
#       [
#         "moritapo",
#         2
#       ],
#       [
#         "ken",
#         3
#       ],
#       [
#         "hana",
#         1
#       ]
#     ]
#   ]
# ]

このように、テーブルの参照関係を逆にたどる検索ができました。

4.6.3. インデックス付きジオサーチ

Groongaでは位置情報のカラムに対して、インデックスを付与することが出来ます。大量の位置情報レコードを検索する場合に、検索速度が速くなります。

実行例:

table_create --name GeoSite --flags TABLE_HASH_KEY --key_type ShortText
# [[0, 1337566253.89858, 0.000355720520019531], true]
column_create --table GeoSite --name location --type WGS84GeoPoint
# [[0, 1337566253.89858, 0.000355720520019531], true]
table_create --name GeoIndex --flags TABLE_PAT_KEY --key_type WGS84GeoPoint
# [[0, 1337566253.89858, 0.000355720520019531], true]
column_create --table GeoIndex --name index_point --type GeoSite --flags COLUMN_INDEX --source location
# [[0, 1337566253.89858, 0.000355720520019531], true]
load --table GeoSite
[
 {"_key":"http://example.org/","location":"128452975x503157902"},
 {"_key":"http://example.net/","location":"128487316x502920929"}
]
# [[0, 1337566253.89858, 0.000355720520019531], 2]
select --table GeoSite --filter 'geo_in_circle(location, "128515259x503187188", 5000)' --output_columns _key,location
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         1
#       ],
#       [
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "location",
#           "WGS84GeoPoint"
#         ]
#       ],
#       [
#         "http://example.org/",
#         "128452975x503157902"
#       ]
#     ]
#   ]
# ]

これらのインデックスは、位置情報レコードを用いてソートする場合に使われます。

実行例:

select --table GeoSite --filter 'geo_in_circle(location, "128515259x503187188", 50000)' --output_columns _key,location,_score --sort_keys '-geo_distance(location, "128515259x503187188")' --scorer '_score = geo_distance(location, "128515259x503187188")'
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         2
#       ],
#       [
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "location",
#           "WGS84GeoPoint"
#         ],
#         [
#           "_score",
#           "Int32"
#         ]
#       ],
#       [
#         "http://example.org/",
#         "128452975x503157902",
#         2054
#       ],
#       [
#         "http://example.net/",
#         "128487316x502920929",
#         6720
#       ]
#     ]
#   ]
# ]