groongaでトークナイザーをカスタマイズして複数形や動詞の変化に対応した検索をするには

> もっとgroongaを知ってもらおう!ということで週刊groongaをはじめました。毎週木曜にgroongaやmroonga、rroongaのトピックを投稿予定です。

[gihyo.jp](http://gihyo.jp/)さんでgroongaの隔週更新連載をしています。第8回の記事も公開されたので、一読をおすすめします。

* [「第8回　CentOS6でのRPMパッケージを用いた MySQL 5.6 & mroonga & PHP 5.4 環境の作り方」](http://gihyo.jp/dev/clip/01/groonga/0008)

第1回から第7回までの過去記事については、[隔週連載groonga](http://gihyo.jp/dev/clip/01/groonga)のページを参照してください。

# はじめに

オープンソースの[カラムストア機能付き全文検索エンジンgroonga](http://groonga.org/ja/)を公開しています。最新のバージョンは2013年7月29日にリリースした[3.0.6](http://groonga.org/ja/docs/news.html#release-3-0-6)です。

今回は、groongaでトークナイザーをカスタマイズして複数形や動詞の変化に対応した検索をする方法を紹介します。

# groongaのトークナイザーで困ること

最近、groongaのメーリングリストに[groongaのトークナイザの改善について](http://sourceforge.jp/projects/groonga/lists/archive/dev/2013-August/001572.html)という投稿がありました。

その投稿の中に英文を空白区切りでトークナイズした場合、複数形等のゆらぎがある場合にはうまく検索できないというものがありました。

例えば、英文を空白区切りでトークナイズする場合を考えてみます。以下のスキーマ定義を使うとしましょう。

```
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のトークナイザの改善について](http://sourceforge.jp/projects/groonga/lists/archive/dev/2013-August/001581.html)にあるように、[トークナイザーのサンプル](https://github.com/groonga/groonga-tokenizer-sample)が最近になって公開されました。

そこで、このサンプルを改造してトークナイザーをカスタマイズしてみました。

ポイントは[WordNet](http://wordnet.princeton.edu/wordnet/)を使用してみたことです。WordNetで複数形や動詞の変化を原形に戻してトークナイザーが扱うことで検索への影響をなくしたことです。

# TokenWordNet プラグインのインストール

WordNetを使うために必要なパッケージをあらかじめインストールします。Ubuntu 13.04だと以下のコマンドを実行します。(groongaはすでにインストール済みとします)

```sh
% 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に興味を持ったなら、まずは[インストール](http://groonga.org/ja/docs/install.html)して試してみてください。

groongaの基本的な動作を知るための[チュートリアル](http://groonga.org/ja/docs/tutorial.html)もあります。インストールしたら試してみてください。