もっとgroongaを知ってもらおう!ということで週刊groongaをはじめました。毎週木曜にgroongaやmroonga、rroongaのトピックを投稿予定です。
gihyo.jpさんでgroongaの隔週更新連載をしています。第8回の記事も公開されたので、一読をおすすめします。
第1回から第7回までの過去記事については、隔週連載groongaのページを参照してください。
はじめに
オープンソースのカラムストア機能付き全文検索エンジンgroongaを公開しています。最新のバージョンは2013年7月29日にリリースした3.0.6です。
今回は、groongaでトークナイザーをカスタマイズして複数形や動詞の変化に対応した検索をする方法を紹介します。
groongaのトークナイザーで困ること
最近、groongaのメーリングリストにgroongaのトークナイザの改善についてという投稿がありました。
その投稿の中に英文を空白区切りでトークナイズした場合、複数形等のゆらぎがある場合にはうまく検索できないというものがありました。
例えば、英文を空白区切りでトークナイズする場合を考えてみます。以下のスキーマ定義を使うとしましょう。
table_create Memos1 TABLE_NO_KEY
column_create Memos1 content COLUMN_SCALAR ShortText
table_create Lexicon1 TABLE_PAT_KEY ShortText --default_tokenizer TokenDelimit
column_create Lexicon1 content_index COLUMN_INDEX|WITH_POSITION|WITH_SECTION Memos1 content
データとしては以下のようなサンプルデータを使うとしましょう。
load --table Memos1
[
{"content": "There is a man"}
{"content": "There are men"}
]
TokenDelimitを使った場合、manでは検索できますが、同時にmenには当然ヒットしません。逆もまた同様です。
> select Memos1 --match_columns Lexicon1.content_index --output_columns "content, _score" --query man
[[0,1375933130.10185,0.000840902328491211],[[[1],[["content","ShortText"],["_score","Int32"]],["There is a man",1]]]]
> select Memos1 --match_columns Lexicon1.content_index --output_columns "content, _score" --query men
[[0,1375933146.75082,0.000227689743041992],[[[1],[["content","ShortText"],["_score","Int32"]],["There are men",1]]]]
manでもmenでも同様に2件ヒットするようにするにはどうすれば良いでしょうか。
トークナイザーを独自に実装する
上記の問題を解決するには、クエリ展開を利用する方法もありますが、ありとあらゆる単語について準備するのはあまり現実的ではありません。
他の手段はというと、トークナイザーを独自に実装する必要があります。とはいえ実装例が限られているので、トークナイザーを独自に実装するのはちょっと敷居が高いままでした。
しかし、[groonga-dev,01580] Re: groongaのトークナイザの改善についてにあるように、トークナイザーのサンプルが最近になって公開されました。
そこで、このサンプルを改造してトークナイザーをカスタマイズしてみました。
ポイントはWordNetを使用してみたことです。WordNetで複数形や動詞の変化を原形に戻してトークナイザーが扱うことで検索への影響をなくしたことです。
TokenWordNet プラグインのインストール
WordNetを使うために必要なパッケージをあらかじめインストールします。Ubuntu 13.04だと以下のコマンドを実行します。(groongaはすでにインストール済みとします)
% sudo apt-get install dic-wn wordnet-dev libgroonga-dev
次にプラグインをインストールするために、以下のコマンドを実行します。
% git clone https://github.com/kenhys/groonga-tokenizer-sample.git
% cd groonga-tokenizer-sample
% git checkout tokenwordnet-spike
% ./autogen.sh
% ./configure
% make
% sudo make install
最後に TokenWordNetプラグインを登録します。groongaを対話的に起動して、register tokenizers/wordnet
を実行しプラグインの登録を行います。
% groonga
> register tokenizers/wordnet
[[0,1375927676.66439,0.0298895835876465],true]
実際にトークナイズを試してみましょう。
> tokenize TokenWordNet "There are men"
[[0,1375928008.11803,0.330196857452393],[{"value":"There","position":0},{"value":"be","position":1},{"value":"men","position":2}]]
are
は be
に、men
は man
としてトークナイズされていることがわかります。
では、TokenWordNetを使って試してみましょう。スキーマ定義を以下のようにします。
table_create Memos2 TABLE_NO_KEY
column_create Memos2 content COLUMN_SCALAR ShortText
table_create Lexicon2 TABLE_PAT_KEY ShortText --default_tokenizer TokenWordNet
column_create Lexicon2 content_index COLUMN_INDEX|WITH_POSITION|WITH_SECTION Memos2 content
manでもmenでもどちらでも両方にヒットするとがわかります。
> select Memos2 --match_columns Lexicon2.content_index --output_columns "content, _score" --query man
[[0,1375933575.22055,0.00102448463439941],[[[2],[["content","ShortText"],["_score","Int32"]],["There is a man",1],["There are men",1]]]]
> select Memos2 --match_columns Lexicon2.content_index --output_columns "content, _score" --query men
[[0,1375933601.26185,0.000292062759399414],[[[2],[["content","ShortText"],["_score","Int32"]],["There is a man",1],["There are men",1]]]]
動詞の変化についても同様のことができます。
まとめ
今回は、groongaでトークナイザーをカスタマイズして複数形や動詞の変化に対応した検索をする方法を紹介しました。
TokenWordNetは実験的に作成したプラグインなので動作がとても怪しかったりしますが、トークナイザーを自作するヒントになるかも知れません。
groongaに興味を持ったなら、まずはインストールして試してみてください。
groongaの基本的な動作を知るためのチュートリアルもあります。インストールしたら試してみてください。