SolrのAnalyzerについて

Lucene/Solrには、任意の文書をキーワードで検索するための索引(INDEX)を作るための方法として、Analyzerという仕組みを提供しています。INDEXは文書を検索のための文書の最小要素(Token)が登録され、検索の際にはこのTokenと一致することが検索にhitする基本的な条件となります。その為、このTokenの生成方法によって検索エンジンの使い勝手は完全に変わります。ですからこのAnalyzerの仕組みに関する理解とAnalyzerの選択/設定は、Lucene/Solrを利用するシステムを構築する上で、一番肝の部分と言っても過言ではありません。また、SolrではこのAnalyzerをclassファイルで直接指定することも出来ますが、定義ファイルによるパーツごとの組み合わせとパラメータ設定によって、柔軟にカスタマイズする仕組みも提供しています。今回の記事では、後者の組み合わせ可能な方法について紹介します。

まず、パーツごとの役割についてですが、以下の3つの役割に分かれて構成されています。

No 名称 役割
1 CharFilter Tokenに分割する前の文字列に対して処理を行います
2 Tokenizer 文字列をTokenに分割します
3 TokenFilter 分割されたTokenに対して処理を行います

これらを組み合わせることで様々な検索要件に対応したAnalyzerを、コードを書く事なく簡単に定義する事が可能となっています。それぞれの役割の処理イメージを下記に示します。

このようにそれぞれが細かく役割分担をする事で、再利用しやすい形で提供されています。次に、Analyzerの構成要素である2つのFilterとTokenizerについて紹介します。

CharFIlterについて

CharFilterは、TokenizerがTokenに分割する前処理として、文書に対する単純な文字列処理を行います。文字列処理で文字数が増減する場合は、検索で適切な場所をhighlightするために、CharFilterの実装は文字単位の元の位置(差分)を正しく記録するべきです。
主な用途は単純な文字の置換(一文字→一文字、一文字→複数文字、複数文字→一文字、複数文字→複数文字)や、単純な削除処理(HTMLタグの除去)で使われます。類義語を用いた処理や、単語の品詞によって処理するなど、予めある単位に分割する必要がある場合は、TokenizerによってTokenに分割された後のTokenFilterによって行います。

CharFilterは一つのAnalyzerにつき0個以上の指定が可能です。省略することも出来ますし、複数指定する事で記述した順序で処理を行わせる事も可能です。

Tokenizerについて

TokenizerはAnalyzerの処理の中で最も重要な役割を担います。文書中の文字列を、それぞれのTokenizerのルールでTokenに分割します。最初にも書いた通り、このTokenが検索の為の索引となります。一般的なTokenの生成方法は、文書の単語区切りによる方法です。これは、英語のように、スペースで分割すれば単語ごとに区切ることの出来る言語でだと楽で良いのですが、日本語のように簡単なルールで単語ごとに区切ることの出来ない言語は厄介です。下の例を見て下さい。
===============
MultiSearcher is deprecated
↓スペースで区切る
MultiSearcher | is | deprecated

すもももももももものうち
↓どうやって区切る?
すもも | も | もも | も | もも | の | うち
===============

日本語だと上記のように形態素解析を用いて区切る方法と、単純にN文字ずつ区切るN-Gramという方法が主流で、詳細は色んなサイトで紹介されているのでここでは割愛しますが、それぞれ特性は一長一短です。他にも言語ごとの特性に合わせたものや、英語でもスペース以外で区切るもの、ユニークなものだとファイルパスを区切るTokenizerなんかも提供されています。

Tokenizerは、どういった文言で検索させるかを考えて選ばないと、想定した検索キーワードでhitしなかったり、想定していない結果が返される事があるので、それぞれの特性をよく考えて設定するようにしましょう。

Tokenizerは一つのAnalyzerにつき一つの指定を行います。省略することは出来ず、複数指定する事も出来ません。

TokenFilterについて

TokenFilterは、Tokenizerの後処理として、Tokenの削除や追加、内容自体の編集を行います。一部のFilterでは、CharFilterと似たもの、ほぼ同じものもあります。CharFilterとの明確な使い分けのルールはありませんが、Tokenに関係するものはTokenFilterで行うと良いでしょう。実際にTokenを直接増減させられる為、CharFilterより提供されているクラスの数は多いです。

主な実装としては、一般的な頻出するTokenの削除や同義語のToken追加、動詞などの活用形を基本形へ変換するクラスなどがあります。

TokenFilterはCharFilterと同じように、一つのAnalyzerにつき0個以上の指定が可能です。省略することも出来ますし、複数指定する事で記述した順序で処理を行わせる事も可能です。

まとめ

  • Analyzerは文書をTokenに分割する
  • Analyzerはclassで指定するやり方と、FilterとTokenizerを組み合わせた細かい指定の方法がある
  • 一つのAnalyzerにつき、CharFilterとTokenFilterは複数指定可能で、Tokenizerの指定は一つのみ
  • Tokenizerの前処理がCharFilter、後処理がTokenFilter