Posted by & filed under いろいろ.

このエントリーを含むはてなブックマークはてなブックマーク - Sphinxの全文検索を複合語に強くする このエントリをつぶやくこのWebページのtweets この記事をクリップ!Livedoorクリップ - Sphinxの全文検索を複合語に強くする Share on Tumblr Digg This

最近社内のドキュメントは殆どSphinxで書いてます。しかしどうも検索の精度が悪い、特に複合語がヒットしないと言われたので改善してみました。Sphinxのバージョンはv1.2.2です。

まずはドキュメントに全文検索機能を追加する

こんな方法で追加しました。

  1. sphinx-quickstartでドキュメント作成
  2. conf.pyに全文検索の設定を追加
    python
    html_search_language = 'ja'
    html_search_options = {'type':'default'} # build server using type:mecab
    
  3. make html

改善案1: searchtools.jsを賢くする

_build/html/_static/searchtools.jsパッチを当てます。

生成物にパッチを当てるのは気持ち悪いけど説明の簡便のため、というか私のSphinxやPythonへの理解が低いのでとりあえずこうします。もっとよい方法があれば教えてください。

パッチが何をしてるかというと、元々Sphinxがsearchindex.jsへ出力する索引は転置インデックスindex.termsがオブジェクトリテラルで作成されます。これだと単語が完全一致した時しかインデックスを取得できません。オブジェクトリテラルをソート済みの配列にすることで2分探索+前方一致検索が可能になります。

ソート済みの配列への変換は簡便のためSearch.setIndexでやってます。本来は変換したものをsearchindex.jsに出力したほうがよいでしょう。

こんな配列の索引が出来上がったとします。

1. ["データ", 1]
2. ["データベース", 2]
3. ["移行", 1]

2分探索はSearch._performTermsSearch内でやってます。このbinarySearchは索引内に検索語があるかどうかに関係なく検索語の辞書順での位置を返します。そこから後ろ方向に前方一致検索することで、例えば検索語が「データ」の場合「データ」だけでなく「データベース」もヒットさせることができます。

しかしこれだけだと検索語が複合語の場合、例えば「データ移行」がヒットしません。そこで2分探索の結果を前方向に、今度は検索語が索引内の単語で始まるかどうかをチェックします。そして「データ」がヒットしたら「データ」と「移行」でAND検索したものとしてその結果を返します。「データ」と「移行」が離れてる文書もヒットしますが、それが問題になるようであればdisplayNextItem内の$.ajax#completeで除外すればよいでしょう。

文書の内容や索引の作り方にもよりますが、元のよりは複合語に強くなったと思います。

改善案2: oktaviaを使う

oktaviaは渋川よしきさんが作成したFM-indexによる検索エンジンです。単語の境界に関係なくすべての文書に対し部分一致検索ができます。

非常に魅力的な検索エンジンなのですが、ドキュメントが現行バージョンの1.0に追いついてない、バグと思われる挙動がある、など導入するには少しハードルが高いという印象を受けました。渋川さんに教えていただいた内容を元に私が検証した結果を記しておきます。リビジョンは 8ed26702c90994b621dc426dd16f84debe728799 です。バージョン0.5は安定してるそうです(未検証)。

まずはoktaviaをインストールします。

git clone https://github.com/shibukawa/oktavia.git
cd oktavia
npm install

次に私の作ったパッチをマージします。

oktavia-mkindex-cliで索引を作成します。

grunt build

# -I オプションは「大文字小文字を無視した検索対応」パッチをマージした時のみ有効
./bin/oktavia-mkindex-cli -i ../_build/html/ -r ../_build/html/ -m html -u file -f .body -c 5 -t web -o ../_build/html/searchindex.oktavia.js -I

# search.htmlで使うファイルをコピー
cp ./bin/web/oktavia-jquery-ui.js ../_build/html/oktavia-jquery-ui.js
cp ./templates/sphinx/_static/searchstyle.css ../_build/html/searchstyle.css

oktaviaのファイルをhtmlに追加します。確認だけなら生成した_build/html/search.htmlを変更するのが楽ですが、本来は_templates/searchbox.htmlなどで追加するのがよいと思われます。

 <!-- headに追加 -->
 <script type="text/javascript" src="oktavia-jquery-ui.js"></script>
 <link rel="stylesheet" href="searchstyle.css" type="text/css" />
 <!-- bodyに追加 -->
 <div id="oktavia_search_form" data-index="searchindex.oktavia.js"></div>

search.htmlをブラウザで表示すれば検索可能です。検索結果がポップアップで表示されるなど元のSphinxのUIとは異なるので、元のと同じにしたい場合はoktavia-jquery-ui.jsを変更する必要があります。

searchtools.jsの改善だけでそこそこよくなったので今回はoktaviaの採用を見送りました。ただSphinxの検索エンジンをデフォルトでoktaviaにするという話もあるらしいと聞いています。もしそうなればこのような面倒な改造を行わなくとも、手軽に快適な全文検索ができるようになるでしょう。私はデフォルトでoktaviaが使える未来を望んでます。


関連文書:

  • 関連文書は見つからんがな

Comments are closed.