Elasticsearch 日本語で全文検索 その1

Elasticsearch Japanese Analysis — 日本語全文検索と解析処理モジュール概要


日本語は、分かち書きしない言語のため日本語でちゃんと全文検索できるようにする為には、検索対象のコンテンツの内容、利用するユーザーのスキルなどを考慮しなければ検索精度を向上させることは非常に困難です。逆を言えば、検索対象のコンテンツ、利用するユーザーのスキルが変われば設計が変わってくると言えます。

日本語を検索できるようにトークナイズするには、代表的なものに形態素解析とN-グラムがあります。簡単に説明すると形態素解析を検索で使用すると、単語単位で検索するため、適合率が高く(マッチ度が高いものが検索される)、再現率が低くなります(検索漏れが多くなる)。例えば、キーワード ”京都” では、”東京都” はヒットしません。一方、N-グラムを検索で使用すると、データベースのLike検索に近い検索が可能になり、形態素解析とは逆に、再現率が高くなり、適合率が低くなります。

これらの日本語解析の特徴と、検索するコンテンツの内容、検索を利用するユーザーのスキルなどをもとに、日本語をどのように検索できるシスムを構築するのか考える必要があります。

例えば、日本語の論文を検索対象にしたケースでは、専門用語が多く、利用するユーザーも専門知識を持ったユーザーが多いと想定できます。また、長い専門用語の検索に使用するキーワードは、頭文字数文字しか入力されないかもしれません。ユーザーは検索結果が多ければ追加のキーワードで絞り込むことができるでしょう。おそらくこのケースで要求されるのは、漏れの少ない検索システムです。この場合は、N−グラムを基本に日本語で検索できるようにすることで、要件を満たすことができます。

Elasticsearch では、フィールド単位で言語解析の方法を設定でき、形態素解析、N-グラムの両方に対応していますので、要件にあわせてどちらを使うのか、または両方を使うのかなど考慮して検索システムを構築することができます。

NOTE:
形態素解析とN-グラムの両方を使う場合は、適合率と再現率は相反するものなので、どちらかをベースに、要所で使い分ける。

Analysis モジュール

日本語をインデックスする為の解析処理を実現するには、Elasticsearch の Analysis モジュールを使用します。精度の高い全文検索を実現する為には、形態素解析やN-グラムによるトークナイズ処理以外にも、文字の正規化や単語の正規化などの加工処理が必要です。

Analysis モジュールは、Analyzer と呼ばれる、トークナイズ処理や文字、単語の加工処理フィルターのパイプラインセットを用途に合わせて複数用意することができます。これらの処理で使用されるトークナイザーやフィルターはElasticsearch にバンドルされているものや、サードパーティで提供されているもの、自前で開発したものを組み合わせてカスタムのアナライザーを定義することが可能です。

また、これらの Analyzer は、インデックスするフィールドマッピング単位で設定可能で、インデックス時と検索時のクエリ文字列処理で使用されます。

NOTE:
インデックス側のアナライザーとサーチ側のアナライザーは基本的には同じもを使用しますが、違うものを使用することも可能です。
Index and Query Processing.

Analyzer

Analyzer は、用途に合わせて複数定義可能で、主にトークナイズ方法とトークナイズされたトークンに対するフィルタリング処理を管理します。実際にフィールドのマッピング指定された Analyzer を通して解析処理が行われます。

Tokenizer

Tokenizerは、トークナイズ方法を定義します。使用するトークナイザーによって各種オプションをカスタマイズすることができます。ひとつの Analyzer 毎に1つのTokenizer を設定することが可能です。

Token Filters

トークナイズ処理の後、トークンに対して加工処理を提供します。1つの Analyzer に対して、0個以上の Filter を定義することが可能です。

Char Filters

トークナイズ処理の前、文字レベルの加工処理を提供します。1つの Analyzer に対して、0個以上の Char Filter を定義することが可能です。

カスタム設定方法

カスタムの Analyzer、Tokenizer、Char Filter、Token Filter の設定はインデックスAPIまたは、設定ファイル($ES_HOME/config/elasticsearch.yml)で設定します。

NOTE:
カスタム設定したアナライザーをドキュメントのインデックスおよびクエリプロセッシングで使用するには、フィールドのマッピング設定時に使用するアナライザーとしてカスタム設定した任意のアナライザーを設定します。
また、ドキュメントをインデックス後インデックス処理側のアナライザーを変更した場合には、再インデックスする必要があることを覚えておいてください。
# 設定例
# edit: $ES_HOME/config/elasticsearch.yml
index:
analysis:
filter:
my_stopwords:
type: stop
stopwords_path: analysis/stopword.txt
tokenizer:
my_tokenizer:
type: standard
analyzer:
my_analyzer:
type: custom
tokenizer: my_tokenizer
filter: [standard, lowercase, my_stopwords]
char_filter:[html_strip]
NOTE:
設定ファイルを変更した場合は、Elasticsearch を再起動して設定を反映します。

あまりお勧めしませんが、default と言う名前のアナライザーを定義することで、デフォルトのアナライザーを変更することもできます。

index:
analysis:
analyzer:
default:
type: custom
tokenizer: kuromoji_tokenizer

動作確認方法

カスタム設定したアナライザーをテストするには、次のコマンドで確認できます。

# API
$ curl -XGET 'localhost:9200/{インデックス名}/_analyze?analyzer={アナライザー名}&pretty=true' -d '{解析対象文字列}'
# 確認コマンド例
curl -XGET 'localhost:9200/sample/_analyze?analyzer=ja&pretty=true' -d '桜が咲き始めました'
{
"tokens" : [ {
"token" : "桜",
"start_offset" : 0,
"end_offset" : 1,
"type" : "word",
"position" : 1
}, {
"token" : "咲き",
"start_offset" : 2,
"end_offset" : 4,
"type" : "word",
"position" : 3
}, {
"token" : "始め",
"start_offset" : 4,
"end_offset" : 6,
"type" : "word",
"position" : 4
} ]
}

次回は日本語検索で使用する主要モジュールについて詳細を説明したいと思います。