Elasticsearch 日本語形態素解析のための文字列正規化の重要性

Kunihiko Kido
Hello! Elasticsearch.
5 min readDec 18, 2014

--

日本語の文章を形態素解析するときは、トークナイズする前に文字列の正規化を済ませて検索精度を向上させよう!

この記事は、Elasticsearch Advent Calendar 2014 の18日目のエントリーです。即席で申し訳ないですが、なんとかまとめましたので是非最後までお付き合いください。

今回は、日本語形態素解析における文字列正規化のお話です。

それでは早速本題に。

非正規化された日本語の文章を形態素解析を使って、なるべく意図したようにトークナイズするためには、全角英数字を半角英数字に正規化したり、半角カタカナを全角カタカナに正規化したり、不要な文字を除外したり、単語ではなく、文字単位での正規化が重要になってきます。

Japanese (kuromoji) Analysis Plugin のページでも紹介されているように、全角英数字や半角カタカナの正規化には、CJK Width Filter がこれまでよく使われているのではないでしょうか? CJK Width Filter は、TokenFilter です。その名の通り、単語単位の処理で使用するフィルターのため、トークナイズ後の単語単位にしか処理することができません。

トークナイザーがNグラムであれば、CJK Width Filter を使っても、おそらく問題はないのですが、このフィルターを形態素解析で使用した場合、トークナイズ後の単語に対してしか正規化できないため、全角英数字を含んだ文字列と、同じ意味の半角英数字を含んだ文字列では最終的な解析結果が異なってしまいます。

例えば、全角の数字を含む「12月限定」 と同じ意味の半角数字を含む 「12月限定」では、それぞれ次のように解析されます。

「12月限定」=> 「12月」「限定」=>「12月」「限定」

「12月限定」=> 「12」「月」「限定」=>「12」「月」「限定」

これはどういう意味かというと、例えばインデックス側のデータが半角の「12月限定」の場合、同じアナライザーを通しても、クエリーが全角の「12月限定」ではマッチしません。(※ AND 検索の場合はマッチしません。OR 検索の場合には「限定」のみがマッチするため、検索結果にはヒットするとは思いますが、検索精度的にはどうかと。。)

さらに、全角半角両方混在では、さらに残念なことに。

「12月限定」=>「1」「2」「月」「限定」=>「1」「2」「月」「限定」

「2月限定」でもマッチしそうです。。。

そこで登場するのが、ICU Analysis Plugin に含まれている ICU Normalization と言うフィルターです。元々は、CJK Width Filter と同じく TokenFilter しかありませんでしたが、今年の5月頃から、CharFilter でも提供されるようになりました。CharFilter はトークナイズ前に単語単位ではなく、文字単位(文章全体)で処理するためのフィルターです。

ICU Normalization CharFilter を使用するには、まず ICU Analysis プラグインをインストールして、"icu_normalizer" を CharFilter に設定するだけで利用できます。

ICU Analysis プラグインのインストール

bin/plugin -install elasticsearch/elasticsearch-analysis-icu/2.4.1

ICU Normalization Charfilter の設定

{
"index" : {
"analysis" : {
"analyzer" : {
"japanese" : {
"tokenizer" : "kuromoji_tokenizer",
"char_filter" : ["icu_normalizer"],
"filter": [...]
}
}
}
}
}

※ ICU Normalization CharFilter には、name (default : "nfkc_cf") と mode (default : "compose") と言うパラメータがありますが、基本的にはそのままで問題ないはずです。

このアナライザーを使用することで、先ほど例に挙げた文字列は綺麗に、解析結果は同じになります。

「12月限定」=>「12月限定」=>「12」「月」「限定」

「12月限定」 =>「12月限定」=>「12」「月」「限定」

「12月限定」 =>「12月限定」=>「12」「月」「限定」

ちなみに、このフィルターは、英字の小文字化もしてくれるので、Token Filter に、"lowercase" フィルターを入れなくても大丈夫です。英字の小文字化も単語は関係ないので、CharFilterで文字レベルで処理する方が理想的ですね。

今回紹介した ICU Normalization CharFilter に関わらず、非正規化された日本語の文章を形態素解析する場合には、トークナイズする前に文字列の正規化をすませましょう!

短かったですが、参考になれば幸いです。

--

--