読者です 読者をやめる 読者になる 読者になる

CreateField Blog

オープンソースを使って個人でWebサービスを開発・運営していたブログ

Mroongaを使って全文検索Webサービスを作ったときにはまったこと(第1回)

前回のエントリに書いたように、1年半ほどをかけて、独学で特許の全文検索サービスを開発しました。

PatentField | 無料特許検索

最初は、MySQLを使ったこともない状態だったこともあり、かなり紆余曲折しました。Groonga開発チームの懇切な対応もあって、専用サーバ1台で最大で1千万レコード超、400GiB以上のサイズのテキストデータを高速に検索できるようになりました。

今後、何回かにわけて、Mroonga(Groonga)を使って全文検索Webサービスを作ったときにはまったこと、学んだことを全て書き出したいと思います。

全文検索エンジンMroongaとは?

Mroongaは全文検索エンジンであるGroongaをベースとしたMySQL用のストレージエンジンです。Mroongaは、MySQLが使える人であれば、簡単に高速な全文検索機能が使えます。MariaDB10.0系にもバンドルされる予定のようです。

MyISAMラッパーモードでのデータベース構築

最初、データベースをMyISAMで構築したこともあり、ドキュメント(ストレージモード/ラッパーモード)を比較したところ、Groongaのコマンドの実行とカウントの高速化がないぐらいだったため、ラッパーモードでいけるかなぁと思い、ラッパーモードで全文検索を試してみました。

インデックス構築に失敗(mmap編)

数百GiBぐらいのテーブルを10分割し、数十GiBぐらいのテーブルを作成し、インデックス構築をしてみました。しかしながら、以下のようなメッセージがでて、インデックス構築できませんでした。

mmap(4194304,551,432017408)=Cannot allocate memory

これについては、groonga-devのメーリングリストで相談しつつ、vm.max_map_countのカーネルパラメータを見直すことで、このメッセージの発生を抑制することができました。今は、このドキュメントに対応方法の詳細が記載されています。

4/15 追記

このドキュメントに記載のように、データベースがメモリサイズを超える場合、vm.overcommit_memoryの設定をしておくことが推奨されています。

vm.overcommit_memory = 1

インデックス構築に失敗(long token編)

Mroongaでは、転置インデックスを作成するためのパーサ(Groongaでは、トークナイザと呼ばれる)として、デフォルトでTokenBigramが用いられます。

通常、Bigramと言えば、2文字ごとにトークンが作成されると思われますが、Mroongaでは、このドキュメントに記載の通り、連続したアルファベット、記号については、1つのトークンとして扱われます。

また、Mroonga(Groonga)では、1つのキーの最大サイズが4096Byteという制限があります。

このため、当時は、アルファベット、記号が4096個以上連続する場合、この制限にひっかかり、インデックス構築できませんでした(今は、4096個以上連続したとしても警告扱いでインデックス構築には失敗しません。)。

これについて、groonga-devのメーリングリストで相談すると、すぐにTokenBigramSplitSymbolAlphaDigit使えばいいよ!という回答が得られました。

非常に親切だなぁと思ったのを覚えております。

TokenBigramSplitSymbolAlphaDigitは、記号、アルファベットについても、2文字で切り出すトークナイザです。これにより、4096Byte以上となるトークンが発生せずに、インデックス構築ができるようになりました。

TokenBigramSplitSymbolAlphaDigitとTokenBigramの検索性能差

アルファベットは、日本語よりも種類が少ないため、アルファベットのBigramでの異なり語数は、たったの26*26種類です。このため、数十GiBクラスの英文のテキストデータをTokenBigramSplitSymbolAlphaDigitでトークナイズすると、TokenBigramに比べて、検索性能が顕著に劣化することが判りました。

TokenBigramSplitSymbolAlphaDigitは、トークンを短く切って一致率を上げるかわりに、検索性能の劣化が生じます。これは、トレードオフの関係となるため、仕方がありません。

しかしながら、上述のように、4096個以上連続するアルファベットが含まれる場合は、インデックス構築することができませんでした。

groonga-devのメーリングリストで相談すると、too long tokenを警告メッセージにして、4096Byte以上の長いトークンについては無視するように改修してくれました。

これもものすごい速い対応で感動した覚えがあります。

これにより、数十GiBのデータベースについては、インデックス構築に失敗せず、MyISAMのラッパーモードで高速に全文検索できるようになりました。

その後、「ストレージモードの検討」、「複数条件の絞り込み」、「Spiderストレージエンジンを使ったデータベースシャーディングの検討」、「ドリルダウン検索の検討」、「テーブルの統合」、「テーブルの統合によるカラムサイズ制限」、「テーブルの統合によるインデックス構築失敗再び」、「トークナイザのカスタマイズ」、「ノーマライザのカスタマイズ」、「スニペットがうまく取得できない場合がある」、等、様々な問題にぶちあたります。

それは、またの機会に書き連ねたいと思います。

おわりに

Groonga、Mroongaは日本で活発に開発が行われており、毎月29日にバージョンアップされています。

最近、全文検索エンジンとしては、Elasticsearchなどが流行ってきているようですが、Mroongaには、MySQLのストレージエンジンで簡単に全文検索が使えるというメリットもあり、Groongaも、他の全文検索エンジンに負けないほど高速なはずです(Lucene系の全文検索エンジンと比較したことがないからわかりませんが速いはず。)。

また、先月には、Droongaと呼ばれる分散型の全文検索システムもメジャーリリースされています。

困ったことがあれば、groonga-devのメーリングリストで相談すると、ものすごく親切に対応してくれるはずです。(Twitterでつぶやくだけでも、どこからともなく、親切な方がやってきて助け舟が入る可能性も。。私が知っている範囲なら、私に聞いてもらっても大丈夫です。)

全文検索システムを使いたい場合は、Groonga、Mroongaがおすすめです。

足りない部分があるなら、どんどん提案したり、改修していけたらいいなぁと思います。日本製のGroongaがもっと普及して欲しいと思っています。

全文検索システムを使いたい場合は、Groonga、Mroongaがかなりおすすめです。

4/13 記事を追加しました。
ストレージモードとGroongaの利点について説明しています。
Mroongaのラッパーモードからストレージモードに変えた理由 - CreateField Blog

4/15 記事を追加しました。
ストレージモードにしてはまったことについて説明しています。
数百GiBの全文検索用データベースをMroongaのストレージモードにしてはまったこと - CreateField Blog

6/26 記事を追加しました。
Groongaがあまり得意でない類似文書検索に連想検索エンジンGETAssocを使った話

2014-11-29(土)13:30 - 17:30
年に1度のGroongaに関するイベントがあります。Groongaを使っている人、興味がある人は参加してみてはいかがでしょうか。

全文検索エンジンGroongaを囲む夕べ5 - Groonga | Doorkeeper