MySQL5.1で日本語全文検索(その5;Mecabで分かち書きしてみるの巻)
前回は、Fulltext Parser ProjectのMecabパーサーと、Bigramパーサーを操作してみた。
Mecabパーサーを使うのであれば、Mecabで分かち書きしたテキストをMySQL5.1のデフォルトのパーサーを使って、FULLTEXTインデックスを張ったらどうなるのだろう??
MeCabの処理を分離しておくことで、少なくともMySQL5.1の「公式ルール」通りに動作するはずだし、「なにかいいこと」があるんじゃないか、と思って実験してみた。
- あらかじめ、MeCabで分かち書きしておく。
- MySQL5.1では、MYISAMストレージエンジンでdefault charset=UTF8, collate=utf8_unicode_ciでテーブルを作る。
- TEXT型のカラムを作成し、デフォルトのパーサでFULLTEXTインデックスをはる。(型と容量については、MySQLの公式ページを参照) TEXT型で2^16のサイズ。
- WHERE MATCH AGAINSTで検索する。
mysql> create table nml (c text, fulltext(c)) engine=MYISAM default charset=UTF8 collate=utf8_unicode_ci;
これまでと同様にWikipediaのクリスマスローズ、オミナエシ、オシロイバナの記述をつかって、これをMecabで分かち書きし、まずは、3レコードで実験してみた。
mysql> set names utf8; mysql> select count(*) from nml where match(c) against('+オミナエシ' IN BOOLEAN MODE); +----------+ | count(*) | +----------+ | 1 | +----------+ 1 row in set (0.00 sec) select count(*) from nml where match(c) against('*オミナ' IN BOOLEAN MODE); +----------+ | count(*) | +----------+ | 0 | +----------+ 1 row in set (0.00 sec) mysql> select count(*) from nml where match(c) against('+オミナエシ' IN BOOLEAN MODE); +----------+ | count(*) | +----------+ | 1 | +----------+ 1 row in set (0.00 sec) mysql> select count(*) from nml where match(c) against('+オミナエシ +女郎' IN BOOLEAN MODE); +----------+ | count(*) | +----------+ | 0 | +----------+ 1 row in set (0.00 sec) mysql> select count(*) from nml where match(c) against('+オミナエシ +女郎花' IN BOOLEAN MODE); +----------+ | count(*) | +----------+ | 1 | +----------+ 1 row in set (0.00 sec) mysql> select count(*) from nml where match(c) against('オミナエシ 女郎花' IN BOOLEAN MODE); +----------+ | count(*) | +----------+ | 1 | +----------+ 1 row in set (0.00 sec) mysql> select count(*) from nml where match(c) against('+オミナエシ +女郎*' IN BOOLEAN MODE); +----------+ | count(*) | +----------+ | 1 | +----------+ 1 row in set (0.00 sec) mysql> select count(*) from nml where match(c) against('+オミナ* +女郎*' IN BOOLEAN MODE); +----------+ | count(*) | +----------+ | 1 | +----------+ 1 row in set (0.00 sec) mysql> select count(*) from nml where match(c) against('+オミナ* -女郎*' IN BOOLEAN MODE); +----------+ | count(*) | +----------+ | 0 | +----------+ 1 row in set (0.00 sec) mysql> select count(*) from nml where match(c) against('+オミナ* -女郎*' IN BOOLEAN MODE); +----------+ | count(*) | +----------+ | 0 | +----------+ 1 row in set (0.00 sec)
思った通りの挙動。
collate を utf8_unicode_ci にしているので、以下のように全角と半角の違いは吸収される。
mysql> select count(*) from nml where match(c) against('+オミナエシ -女郎*' IN BOOLEAN MODE); +----------+ | count(*) | +----------+ | 0 | +----------+ 1 row in set (0.00 sec) mysql> select count(*) from nml where match(c) against('+オミナエシ +女郎*' IN BOOLEAN MODE); +----------+ | count(*) | +----------+ | 1 | +----------+ 1 row in set (0.00 sec)
最後に、30,000件にデータを増やしてみた。キャッシュを使わない状態で、以下の数字となり、MeCabパーサーを使った場合と同様のレスポンスとなった(2回目以降の検索は、100倍ほど高速になるが、FULLTEXTインデックスだから、評価してもあんまり意味がないように思われる)
mysql> select count(*) from nml where match(c) against(+'オミナエシ' IN BOOLEAN MODE); +----------+ | count(*) | +----------+ | 10000 | +----------+ 1 row in set (4.14 sec)