groongaでは、 select コマンドにquery_expansionパラメータを指定することによって、ユーザが指定した検索文字列を適宜拡張することが可能です。
たとえば、ユーザが'シークヮーサー'という文字列で検索した場合に、'シークヮーサー OR シークァーサー'で検索した場合と同一の結果を返すことによって、本来ユーザが必要とする結果をよりもれなく検索できるようになります。
クエリ拡張機能を使用するためには、検索対象となる文書を格納するテーブル(ここでは文書テーブルと呼びます)以外に、ユーザの指定した検索文字列を置換するためのテーブル(ここでは置換テーブルと呼びます)を準備します。置換テーブルでは、その主キーが置換前の文字列となり、文字列型(ShortText)のカラムの値が置換後の文字列となります。
TODO: 文字列型のベクターカラムでも可能であり、その場合は各要素をORでつなげたものに置換されるということを記述する。
実際に文書テーブルと置換テーブルを作成してみましょう。
実行例:
> table_create Doc TABLE_PAT_KEY ShortText
[[0,1317212801.95257,0.054058921],true]
> column_create Doc body COLUMN_SCALAR ShortText
[[0,1317212802.2071,0.040301713],true]
> table_create Term TABLE_PAT_KEY|KEY_NORMALIZE ShortText --default_tokenizer TokenBigram
[[0,1317212802.44812,0.027340933],true]
> column_create Term Doc_body COLUMN_INDEX|WITH_POSITION Doc body
[[0,1317212802.676,0.079743674],true]
> table_create Synonym TABLE_PAT_KEY ShortText
[[0,1317212802.95629,0.03656858],true]
> column_create Synonym body COLUMN_SCALAR ShortText
[[0,1317212803.19316,0.040515932],true]
> load --table Doc
> [
> {"_key": "001", "body": "すっぱいブドウと甘いシークァーサー"},
> {"_key": "002", "body": "シークヮーサージュースとゴーヤチャンプル"},
> ]
[[0,1317212803.43422,0.80056314],2]
> load --table Synonym
> [
> {"_key": "シークァーサー", "body": "(シークァーサー OR シークヮーサー)"},
> {"_key": "シークヮーサー", "body": "(シークァーサー OR シークヮーサー)"},
> ]
[[0,1317212804.43524,0.801037492],2]
この例では、ユーザが"シークァーサー"と入力しても、"シークヮーサー"と入力しても、それぞれの異なる表記の文書をもれなく検索するための置換テーブルを作成しています。
それでは実際に、準備した置換テーブルを使ってみましょう。まずは、query_expansionパラメータを指定せずにselectコマンドを使って検索してみます。
実行例:
> select Doc --match_columns body --query "シークァーサー"
[[0,1317212805.4371,0.000567851],[[[1],[["_id","UInt32"],["_key","ShortText"],["body","ShortText"]],[1,"001","すっぱいブドウと甘いシークァーサー"]]]]
> select Doc --match_columns body --query "シークヮーサー"
[[0,1317212805.63859,0.000387831],[[[1],[["_id","UInt32"],["_key","ShortText"],["body","ShortText"]],[2,"002","シークヮーサージュースとゴーヤチャンプル"]]]]
指定された文字列に完全に一致するレコードのみがそれぞれヒットします。次に、query_expansionパラメータに、準備したSynonymテーブルのbodyカラムを指定してみましょう。
実行例:
> select Doc --match_columns body --query "シークァーサー" --query_expansion Synonym.body
[[0,1317212805.84016,0.000441852],[[[2],[["_id","UInt32"],["_key","ShortText"],["body","ShortText"]],[1,"001","すっぱいブドウと甘いシークァーサー"],[2,"002","シークヮーサージュースとゴーヤチャンプル"]]]]
> select Doc --match_columns body --query "シークヮーサー" --query_expansion Synonym.body
[[0,1317212806.04176,0.000580261],[[[2],[["_id","UInt32"],["_key","ShortText"],["body","ShortText"]],[1,"001","すっぱいブドウと甘いシークァーサー"],[2,"002","シークヮーサージュースとゴーヤチャンプル"]]]]
どちらのクエリ文字列も、"(シークァーサー OR シークヮーサー)"という文字列に置換されてから検索されるため、表記の揺れを吸収して検索できるようになりました。