Solr4.0のデフォルトのschema.xmlを読む

こんにちは。

前回Herokuで全文検索事情について書きましたが結局は自前でSolrのサーバを立てることになりそうです。

Herokuには前回とりあげた以外にもElasticSearchのラッパーが現在ベータ版のAddOnとしていくつかあるんですが、多分どれも似たり寄ったりです。(--

結局のところ日本人スタッフのいない環境で作成された全文検索サービスはもれなく日本では使い物にならん!という結論に達しました。(^^;;;

□□□□

そんな訳で最近よくSolrをいじっているわけですが、日本語での全文検索エンジンを構築する場合に早い段階で意思決定しなければならない事柄の一つに単語分割にN-gramと形態素解析のどちらを使用するか?という命題があります。

この両者がどういうアルゴリズムであるか?またそれぞれにどういうメリット・デメリットがあるか?という点については多くのサイトで解説されているのでそれらのサイトを参照してもらえば良いかと思います。
ここではSolrに標準でバンドルされているschema.xml(example/solr/collection1/conf/schema.xml)から、実際にどのように文章が分割されインデックスされるのかを掘り下げてみようと思います。

 

★N-gram

schema.xmlの中でN-gram(厳密には2文字分割のBi-gram)の定義は「text_cjk」という名前のfieldTypeで行われています。

以下にその定義を示します。

 

    <!-- CJK bigram (see text_ja for a Japanese configuration using morphological analysis) -->
    <fieldType name="text_cjk" class="solr.TextField" positionIncrementGap="100">
      <analyzer>
        <tokenizer class="solr.StandardTokenizerFactory" />
        <!-- normalize width before bigram, as e.g. half-width dakuten combine  -->
        <filter class="solr.CJKWidthFilterFactory" />
        <!-- for any non-CJK -->
        <filter class="solr.LowerCaseFilterFactory" />
        <filter class="solr.CJKBigramFilterFactory" />
      </analyzer>
    </fieldType>

 

定義ファイルのそれぞれの要素や属性の詳細な解説はパスします。
ここでは「tokenizer」が単語分割を行うクラスの指定、「filter」が分割された単語のフィルタリングや正規化を行うクラス、という程度の理解があれば十分です。(というか、そもそもちゃんとドキュメント読んでないので僕の理解もその程度です。。。(^^;;;)

さて、この定義を見ていくとまず先頭のtokenizer定義でStandardTokenizerFactoryという全く特殊性の感じられないTokenizerが使用されていることがわかります。
実際、このTokenizerは英文などのホワイトスペース区切りの単語分割でも使用される最も一般的なTokenizerです。日本語の文章に対してこのTokenizerを適用した場合は英文や連続するカタカナなどは1単語として認識されますが、それ以外のひらがなや漢字などはすべて1文字1単語として分割されます。

実際にBi-gramを作成しているのは一番最後に定義されているCJKBigramFilterFactoryです。(つまりFilterで単語分割位置を変更するというややトリッキーな実装になっている)
ものの本によると昔はCJKTokenizerFactoryというのがあって、いきなりN-gramを作っていたようですが多分今の構成の方が後続のFilterを適用しやすいのでこのような実装になっているのではないかと思います。

間に挟まっている2つのFilterの役割は以下です。

 

CJKWidthFilterFactory

半角カナは全角に、全角英数字は半角に正規化します。

 

LowerCaseFilterFactory

英大文字をすべて小文字に正規化します。

 

要するに半角全角の違いや大文字小文字の違いはインデックス作成の際に吸収されており、検索者は気にする必要がないということです。

 

★形態素解析(Kuromoji)

次に形態素解析の定義を示します。
コメントが多いので削ろうか迷いましたが、これだけで定義内容がわかるほどの情報量があるのでそのまま残しました。

 

    <fieldType name="text_ja" class="solr.TextField" positionIncrementGap="100" autoGeneratePhraseQueries="false">
      <analyzer>
      <!-- Kuromoji Japanese morphological analyzer/tokenizer (JapaneseTokenizer)

           Kuromoji has a search mode (default) that does segmentation useful for search.  A heuristic
           is used to segment compounds into its parts and the compound itself is kept as synonym.

           Valid values for attribute mode are:
              normal: regular segmentation
              search: segmentation useful for search with synonyms compounds (default)
            extended: same as search mode, but unigrams unknown words (experimental)

           For some applications it might be good to use search mode for indexing and normal mode for
           queries to reduce recall and prevent parts of compounds from being matched and highlighted.
           Use <analyzer type="index"> and <analyzer type="query"> for this and mode normal in query.

           Kuromoji also has a convenient user dictionary feature that allows overriding the statistical
           model with your own entries for segmentation, part-of-speech tags and readings without a need
           to specify weights.  Notice that user dictionaries have not been subject to extensive testing.

           User dictionary attributes are:
                     userDictionary: user dictionary filename
             userDictionaryEncoding: user dictionary encoding (default is UTF-8)

           See lang/userdict_ja.txt for a sample user dictionary file.

           Punctuation characters are discarded by default.  Use discardPunctuation="false" to keep them.

           See http://wiki.apache.org/solr/JapaneseLanguageSupport for more on Japanese language support.
        -->
        <tokenizer class="solr.JapaneseTokenizerFactory" mode="search" />
        <!--<tokenizer class="solr.JapaneseTokenizerFactory" mode="search" userDictionary="lang/userdict_ja.txt" />-->
        <!-- Reduces inflected verbs and adjectives to their base/dictionary forms (辞書形) -->
        <filter class="solr.JapaneseBaseFormFilterFactory" />
        <!-- Removes tokens with certain part-of-speech tags -->
        <filter class="solr.JapanesePartOfSpeechStopFilterFactory" tags="lang/stoptags_ja.txt" enablePositionIncrements="true" />
        <!-- Normalizes full-width romaji to half-width and half-width kana to full-width (Unicode NFKC subset) -->
        <filter class="solr.CJKWidthFilterFactory" />
        <!-- Removes common tokens typically not useful for search, but have a negative effect on ranking -->
        <filter class="solr.StopFilterFactory" ignoreCase="true" words="lang/stopwords_ja.txt" enablePositionIncrements="true" />
        <!-- Normalizes common katakana spelling variations by removing any last long sound character (U+30FC) -->
        <filter class="solr.JapaneseKatakanaStemFilterFactory" minimumLength="4" />
        <!-- Lower-cases romaji characters -->
        <filter class="solr.LowerCaseFilterFactory" />
      </analyzer>
    </fieldType>

 

TokenizerはKuromojiという形態素解析エンジンを利用したJapaneseTokenizerFactoryです。userDictionary属性でユーザー辞書を指定することができます。(サンプルとしてバンドルされているユーザー辞書には「朝青龍」とか定義されていてちょっと和みます。)

以下次の順序でFilterが適用されていきます。

 

JapaneseBaseFormFilterFactory

このFilterは動詞などの活用形を正規化します。
例えば(動詞と判定された)「し」を「する」に変換するみたいな。

 

JapanesePartOfSpeechStopFilterFactory

不要な品詞を削除します。
どの品詞が不要かはtags属性で指定したファイル内に記述します。
サンプルとしてバンドルされているファイルでは助詞、助動詞、接続詞、記号が削除されるようになっています。

 

CJKWidthFilterFactory

N-gramでも使用されていた半角カナと全角英数字を正規化するFilterです。

 

StopFilterFactory

words属性で指定されたファイルに記述されている単語を削除します。
サンプルとしてバンドルされているファイルでは「その」とか「そして」などのおよそ検索に使用されそうにない単語が100個程度定義されています。

 

JapaneseKatakanaStemFilterFactory

カタカナの最後の長音を削除します。ただし文字数がminimumLengthに満たないものでは削除されません。
例えば「ユーザー」は「ユーザ」に正規化されますが「コピー」はそのままです。

 

LowerCaseFilterFactory

N-gramでも使用されていた英大文字を小文字にするFilterです。

 

★考察

ここまで見てきた通りN-gramより形態素解析の方がきめ細かい設定が可能です。

ここではとりあげなかった有用そうなFilterとしてSynonymFilterという単語の同一視が可能なFilterもありますが、これもN-gramでは使用できません。

直観的には形態素解析の方が精度が高そうな気がしますが、品詞の削除などによって元の文章がインデックス作成時に破壊されているという点は大きなポイントだと思います。
例えば人名や書籍のタイトルなどを対象とする場合はN-gramの方が向いているように思います。

SolrではFieldTypeの定義によってどのように文章が分割されるのかが管理ツールで簡単に確認できます。そのため開発中には辞書や定義ファイルを変更しながらチューニングを行うことも可能ですが、その場合インデックスの再構築が必要なはずなので扱う文書量が多い場合は運用中に変更することは難しいかもしれません。

ここから先は実際に開発を始めてみないと何とも言えないですね。(^^;;;

コメント(0)