4.11. クエリ拡張

Groongaでは、 select コマンドにquery_expanderパラメータを指定することによって、ユーザが指定した検索文字列を適宜拡張することが可能です。

たとえば、ユーザが'シークヮーサー'という文字列で検索した場合に、'シークヮーサー OR シークァーサー'で検索した場合と同一の結果を返すことによって、本来ユーザが必要とする結果をよりもれなく検索できるようになります。

4.11.1. 準備

クエリ拡張機能を使用するためには、検索対象となる文書を格納するテーブル(ここでは文書テーブルと呼びます)以外に、ユーザの指定した検索文字列を置換するためのテーブル(ここでは置換テーブルと呼びます)を準備します。置換テーブルでは、その主キーが置換前の文字列となり、文字列型(ShortText)のカラムの値が置換後の文字列となります。

TODO: 文字列型のベクターカラムでも可能であり、その場合は各要素をORでつなげたものに置換されるということを記述する。

実際に文書テーブルと置換テーブルを作成してみましょう。

Execution example:

table_create Doc TABLE_PAT_KEY ShortText
# [[0, 1337566253.89858, 0.000355720520019531], true]
column_create Doc body COLUMN_SCALAR ShortText
# [[0, 1337566253.89858, 0.000355720520019531], true]
table_create Term TABLE_PAT_KEY|KEY_NORMALIZE ShortText --default_tokenizer TokenBigram
# [[0, 1337566253.89858, 0.000355720520019531], true]
column_create Term Doc_body COLUMN_INDEX|WITH_POSITION Doc body
# [[0, 1337566253.89858, 0.000355720520019531], true]
table_create Synonym TABLE_PAT_KEY ShortText
# [[0, 1337566253.89858, 0.000355720520019531], true]
column_create Synonym body COLUMN_SCALAR ShortText
# [[0, 1337566253.89858, 0.000355720520019531], true]
load --table Doc
[
{"_key": "001", "body": "すっぱいブドウと甘いシークァーサー"},
{"_key": "002", "body": "シークヮーサージュースとゴーヤチャンプル"},
]
# [[0, 1337566253.89858, 0.000355720520019531], 2]
load --table Synonym
[
{"_key": "シークァーサー", "body": "(シークァーサー OR シークヮーサー)"},
{"_key": "シークヮーサー", "body": "(シークァーサー OR シークヮーサー)"},
]
# [[0, 1337566253.89858, 0.000355720520019531], 2]

この例では、ユーザが"シークァーサー"と入力しても、"シークヮーサー"と入力しても、それぞれの異なる表記の文書をもれなく検索するための置換テーブルを作成しています。

4.11.2. 検索

それでは実際に、準備した置換テーブルを使ってみましょう。まずは、query_expanderパラメータを指定せずにselectコマンドを使って検索してみます。

Execution example:

select Doc --match_columns body --query "シークァーサー"
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         1
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "body",
#           "ShortText"
#         ]
#       ],
#       [
#         1,
#         "001",
#         "すっぱいブドウと甘いシークァーサー"
#       ]
#     ]
#   ]
# ]
select Doc --match_columns body --query "シークヮーサー"
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         1
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "body",
#           "ShortText"
#         ]
#       ],
#       [
#         2,
#         "002",
#         "シークヮーサージュースとゴーヤチャンプル"
#       ]
#     ]
#   ]
# ]

指定された文字列に完全に一致するレコードのみがそれぞれヒットします。次に、query_expanderパラメータに、準備したSynonymテーブルのbodyカラムを指定してみましょう。

Execution example:

select Doc --match_columns body --query "シークァーサー" --query_expander Synonym.body
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         2
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "body",
#           "ShortText"
#         ]
#       ],
#       [
#         1,
#         "001",
#         "すっぱいブドウと甘いシークァーサー"
#       ],
#       [
#         2,
#         "002",
#         "シークヮーサージュースとゴーヤチャンプル"
#       ]
#     ]
#   ]
# ]
select Doc --match_columns body --query "シークヮーサー" --query_expander Synonym.body
# [
#   [
#     0,
#     1337566253.89858,
#     0.000355720520019531
#   ],
#   [
#     [
#       [
#         2
#       ],
#       [
#         [
#           "_id",
#           "UInt32"
#         ],
#         [
#           "_key",
#           "ShortText"
#         ],
#         [
#           "body",
#           "ShortText"
#         ]
#       ],
#       [
#         1,
#         "001",
#         "すっぱいブドウと甘いシークァーサー"
#       ],
#       [
#         2,
#         "002",
#         "シークヮーサージュースとゴーヤチャンプル"
#       ]
#     ]
#   ]
# ]

どちらのクエリ文字列も、"(シークァーサー OR シークヮーサー)"という文字列に置換されてから検索されるため、表記の揺れを吸収して検索できるようになりました。