MySQLによる日本語全文検索
php+MySQL+mecabで日本語全文検索システムを作成した。
弊社で提供しているデジタルカタログサービスで提供するデジタルカタログに全文検索機能を実装するためで、実装したサンプルは以下の通り。
JULIA OPEN WATER MANUAL(お客様のご好意によりここで紹介しています。)
MySQLによる日本語全文検索とは?
MySQLにはもともとFULLTEXT型というインデックス機能がある。
これを使用するとGoogleやYahooのような全文検索機能を利用することができるのだが、残念ながら元となる文章が英文のように単語の間にスペースが入っている必要があり、そのままでは日本語では使用できない。
そこで、MySQLのFULLTEXT検索を行うために以下のような方法が使用される。
- mecabなどの分かち書きシステムを利用してインデックスを構築する。
- n-gramを使用してインデックスを構築する。
それぞれの技術的な詳細はここでは紹介しないが、上記の2種類の方法には以下のようなメリット/デメリットがある。
mecabを使用した全文検索のメリット/デメリット
メリット
- LIKEを使用した検索に比べて非常に高速に動作する。
- 関連性が高いものから低いものへ自動的にソートされる。
- 文字セットをutf8_unicode_ciにすれば大文字小文字や全角半角等を同じものとして検索できる。
デメリット
- データのinsertやupdateに時間がかかる。
- 分かち書きの精度により、検出漏れがあり得る。
n-gramを使用した際のメリット/デメリット
メリット
- LIKEを使用した検索に比べて非常に高速に動作する。
- アルゴリズムが単純で特別なライブラリのインストールを必要としない。
- mecabを使用した場合に比べて検索漏れが生じない。
デメリット
- 誤検出が発生しうる。(「日本人」と検索した場合に「本人は日本」もマッチする)
- 関連性によるソートがうまく動作しない。
- insertやupdateに時間がかかる。
今回使用した方法
以上の結果をふまえていろいろテストした結果、mecabを使用して検索を行うこととした。
事例で紹介したサンプルでは、pdfから抽出したテキストをmecabで分かち書きしてMySQLにinsertしFULLTEXTインデックスを適用した。
mecabを用いた際の最も大きなデメリットとなる検出漏れの問題については、検索に用いるキーワードもmecabにより分かち書きして、さらにmatch() 〜 against()を使用することで分かち書きされた単語によるOR条件で検索されるため、ほとんど問題にならないことがわかった。
ORで検索されると(正確にはmatch()〜against())、例えば「最大水深」という単語が「最大」と「水深」に分割され、それらのどちらか一方の単語しか無いページも検索されてしまう。
しかし関連度順にソートされるため「最大水深」とある文書がきちんと上位表示されるため、結果的に使い勝手が非常にいいものとなった。
はまったこと
主にMySQL側の設定であるが、いくつかはまった。
- MySQLデフォルトでは、4文字以下の単語のインデックスが作成されないため日本語には不向きである。そのためmy.cnfのft_min_word_len=1という行をmysqldディレクティブに追加する必要がある。(この値の変更をした場合はインデックスを再構築すること。これを忘れた!)
- against()にIN BOOLEAN MODEを指定すると検索時にANDやOR、ワイルドカードなどを使用できるが、関連度順にソートされないため注意する必要がある。




最近のコメント