MySQLで高速全文検索を実現するMroongaでTokenMeCabが使えないときの対処方法

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

今年も11/29に[全文検索エンジンGroongaを囲む夕べ4](http://atnd.org/events/43461)を開催することになりました。Groongaのいろんな話を聞きたい人にはおすすめです。参加希望者が定員を超えていますが、イベントレポーターをやってくれるなら別枠(1名様)で入れます! 登録が間に合わなかった人は検討してみてください。詳細は[協力者募集](http://atnd.org/events/43461#help-us)を参照してください。

# はじめに

MySQLで高速に全文検索するためのオープンソースのストレージエンジンとして[Mroonga](http://mroonga.org/ja/) (むるんが)を公開しています。
最新のバージョンは2013年10月29日にリリースした[3.09](http://mroonga.org/ja/docs/news.html#release-3-09-2013-10-29)です。

今回は、Mroongaで全文検索をするときにMeCabが使えなくて困ったときの対処方法を紹介します。

# 問題の内容

Mroongaでは、トークナイザーとしてMeCabが使えるようになっています。

そこで、Mroongaをインストールしたあとに検索を試してみようと次のようなサンプルデータを用意したとします。

```
use test;
DROP TABLE IF EXISTS test_mecab;
CREATE TABLE test_mecab (id int primary key auto_increment, content varchar(255), fulltext index(content) comment 'parser = "TokenMecab"') engine = mroonga default charset utf8;
INSERT INTO test_mecab (content) VALUES ("明日の天気は晴れでしょう。");
INSERT INTO test_mecab (content) VALUES ("明日の天気は雨でしょう。");
INSERT INTO test_mecab (content) VALUES ("明日の東京都の天気は晴れでしょう。");
INSERT INTO test_mecab (content) VALUES ("明日の京都の天気は雨でしょう。");
```

``東京都``で検索してみましょう。

```
mysql> SELECT * FROM test_mecab WHERE MATCH(content) AGAINST('東京都');
+----+-----------------------------------------------------+
| id | content                                             |
+----+-----------------------------------------------------+
|  3 | 明日の東京都の天気は晴れでしょう。                  |
|  4 | 明日の京都の天気は雨でしょう。                      |
+----+-----------------------------------------------------+
2 rows in set (0.00 sec)
```

すると、京都も検索できていますね。

今度は、``京都``で検索してみましょう。

```
mysql> SELECT * FROM test_mecab WHERE MATCH(content) AGAINST('京都');
+----+-----------------------------------------------------+
| id | content                                             |
+----+-----------------------------------------------------+
|  3 | 明日の東京都の天気は晴れでしょう。                  |
|  4 | 明日の京都の天気は雨でしょう。                      |
+----+-----------------------------------------------------+
2 rows in set (0.00 sec)
```

``東京都``で検索しても、``京都``で検索しても結果がまったく同じになってしまいました。

``東京都``は``東京``と``都``にトークナイズされるのでなんだかうまく動作していなさそうです。

```
% echo  "東京都" |mecab
東京	名詞,固有名詞,地域,一般,*,*,東京,トウキョウ,トーキョー
都	名詞,接尾,地域,*,*,*,都,ト,ト
EOS
```

## TokenMeCabのパッケージはインストールされていますか？

MroongaでTokenMeCabを使うには、あらかじめ``groonga-tokenizer-mecab``をインストールする必要があります。

Groongaでサポートしているディストリビューションであれば、パッケージが提供されているのでそれを使うのが簡単です。

```
% sudo apt-get install groonga-tokenizer-mecab
```

## TokenMeCabが使えるようになっていますか？

パッケージが提供されていない環境では、ソースコードから自前でビルド、インストールしていることでしょう。
そのような場合には、MeCabを有効にしてビルドできていない可能性があります。

TokenMeCabがそもそも使えるようになっているかはGroongaのtokenizeコマンドをMroonga経由で試してみることで確認できます。

```
mysql> select mroonga_command("tokenize TokenMecab '東京都'");
ERROR 1026 (HY000): [tokenize] unknown tokenizer: <TokenMecab>
```

上記のようにunknown tokenizerというエラーが表示されたらMeCabがそもそも使えるようにビルドされていません。

これは、groongaコマンドのバージョン出力からも判断できます。MeCabを有効にしてビルドできていないとmecabが出力されません。

```
% groonga --version
groonga 3.0.9 [linux-gnu,x86_64,utf8,match-escalation-threshold=0,nfkc,msgpack,zlib,lzo,epoll]
```

MeCabが有効になっていると、次のようにmecabが出力されます。

```
% groonga --version
groonga 3.0.9 [linux-gnu,x86_64,utf8,match-escalation-threshold=0,nfkc,mecab,msgpack,zlib,lzo,epoll]
```

MeCabがうまく検出できていない場合には、Groongaの``--with-mecab``、``--with-mecab-config``で環境に合わせて指定してGroongaをビルド、インストールしてください。

MeCabを組込めた状態だとtokenizeコマンドを実行した結果が正しく出力されます。

```
mysql> select mroonga_command("tokenize TokenMecab '東京都'");
+----------------------------------------------------------------+
| mroonga_command("tokenize TokenMecab '東京都'")                |
+----------------------------------------------------------------+
| [{"value":"東京","position":0},{"value":"都","position":1}]    |
+----------------------------------------------------------------+
1 row in set (0.00 sec)
```

## TokenMeCabが使えるようになったけど、うまく検索できていない

groonga-tokenizer-mecabパッケージをあとからインストールしたり、パッケージがない環境ではGroongaをビルド、インストールしなおして使えるようになったけど、検索結果をみると前と同じでうまく検索できていない、という場合にはインデックスが正しく更新されていない可能性があります。

その場合には、ALTER TABLEでインデックスの再構築をします。

```
mysql> ALTER TABLE test_mecab DISABLE KEYS;
Query OK, 0 rows affected (0.00 sec)

mysql> ALTER TABLE test_mecab ENABLE KEYS;
Query OK, 0 rows affected (0.52 sec)
```

すると、``東京都``で検索したときに意図した結果が返ってきます。

```
mysql> SELECT * FROM test_mecab WHERE MATCH(content) AGAINST('東京都');
+----+-----------------------------------------------------+
| id | content                                             |
+----+-----------------------------------------------------+
|  3 | 明日の東京都の天気は晴れでしょう。                  |
+----+-----------------------------------------------------+
1 row in set (0.00 sec)
```

あるいは、明示的にインデックスを張りなおすことでも期待した結果が得られるようになります。

```
mysql> ALTER TABLE test_mecab DROP INDEX content, ADD FULLTEXT INDEX content(content) COMMENT 'parser "TokenMecab"';
Query OK, 4 rows affected (0.34 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM test_mecab WHERE MATCH(content) AGAINST('東京都');
+----+-----------------------------------------------------+
| id | content                                             |
+----+-----------------------------------------------------+
|  3 | 明日の東京都の天気は晴れでしょう。                  |
+----+-----------------------------------------------------+
1 row in set (0.01 sec)
```

# まとめ

今回は、MySQLで高速な全文検索を実現するためのMroongaで、MeCabが使えないときの対処方法を紹介しました。

Mroongaの基本的な動作を知るための[ユーザガイド](http://mroonga.org/ja/docs/userguide.html)もあります。インストールしたら試してみて
ください。

[gihyo.jp](http://gihyo.jp/)さんでGroongaの隔週連載が最終回を迎えました。Mroongaについても記事があるので最新情報と今後に興味があれば一読をおすすめします。該当記事は「最終回　Groongaの今と未来」 です。

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