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

Elasticsearch Japanese Analysis — 日本語全文検索で使用するプラグインと、日本語解析フィルター

Kunihiko Kido
Hello! Elasticsearch.

--

Elasticsearch では、すでに日本語で全文検索する為のトークナイザーやノーマライズなどの加工処理で使用するフィルターなどがビルトインまたは、サードパーティ製のプラグインとして多数存在します。

ここでは、日本語全文検索で使用しそうなトークナイザーやフィルターなどを説明します。

主要モジュール

  • NGram Tokenizer
    N-グラムを提供するトークナイザーです。Elasticsearch にバンドルされています。
  • Japanese (kuromoji) Analysis for Elasticsearch
    日本語形態素解析を提供するプラグインです。各種 Analyzer、Tokenizer、TokenFilterが含まれます。
  • cjk_width Token Filter
    半角・全角などを統一するためのフィルターです。Elasticsearch にバンドルされています。
  • Lowercase Token Filter
    英字の大文字を小文字に変換する為のフィルターです。Elasticsearch にバンドルさています。
  • Synonym Token Filter
    同義語を展開する為のフィルターです。Elasticsearch にバンドルされています。
  • Stop Token Filter
    任意のワード除外する為のフィルターです。Elasticsearch にバンドルされています。
  • HTML Strip Char Filter
    HTML タグを除外する為のフィルターです。Elasticsearch にバンドルされています。

NGram Tokenizer

NGram Tokenizer は、Elasticsearch に標準でバンドルされているトークナイザーです。最小と最大の文字数と、対象にする文字の種類(文字、数字、記号、etc)が設定できます。

# 設定サンプル
# edit: $ES_HOME/config/elasticsearch.yml
index:
analysis:
tokenizer:
ngram_ja_tokenizer:
type: nGram
min_gram: 2
max_gram: 3
token_chars: [letter, digit]
analyzer:
ngram_ja:
type: custom
tokenizer: ngram_ja_tokenizer

一般的に日本語は3グラムと言われているので、最小を2グラム、最大を3グラムに文字が分割されるように設定しています。また、対象のトークンを、letter と digit に限定することで、記号やブランクなどは除外された状態で文字が分割されます。

Elasticsearch を再起動して確認してみます。

# 確認コマンド例
$ curl ‘localhost:9200/sample/_analyze?pretty=true&analyzer=ngram_ja’ -d ‘今日の天気は晴れ’
# 今日/今日の/日の/日の天/の天/の天気/天気/天気は/気は/気は晴/は晴/は晴れ/晴れ

出力結果をみてもわかりますが、Nグラムはオリジナルトークンが解析後膨張します。これは、インデックスのサイズの膨張を意味しています。これもNグラムの特徴です。

Japanese (kuromoji) Analysis for Elasticsearch

Japanese (kuromoji) Analysis for Elasticsearch は、Lucene の日本語解析 kuromoji を Elasticsearch に統合するためのプラグインです。このプラグインを使用することで、Elasticsearch で、日本語を形態素解析で分割された単語単位での日本語検索ができるようになります。また、特定品詞のフィルターや、全角半角の統一など、各種フィルターを使用して、日本語検索の適合率を向上させる為の仕組みを提供しています。

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

次のコマンドで Japanese (kuromoji) Analysis for Elasticsearch プラグインをインストールします。

$ bin/plugin —install elasticsearch/elasticsearch-analysis-kuromoji/2.0.0

analysis-kuromoji と言う名前でインストールされます。Elasticsearch 再起動後、次のコマンドでプラグインがインストールされているかどうかREST APIで確認できます。

$ curl -XGET localhost:9200/_nodes/plugin?pretty
{
“cluster_name” : “elasticsearch”,
“nodes” : {
“0jl5phi3Q0iIVebZinZW6w” : {
“name” : “Wendell Vaughn”,
“transport_address” : “inet[/192.168.1.127:9300]”,
“host” : “kworks92c.local”,
“ip” : “192.168.1.127",
“version” : “1.0.1",
“build” : “5c03844",
“http_address” : “inet[/192.168.1.127:9200]”,
“plugins” : [ {
“name” : “analysis-kuromoji”,
“version” : “NA”,
“description” : “Kuromoji analysis support”,
“jvm” : true,
“site” : false
}
]
}
}
}

kuromoji の主要モジュール

  • kuromoji_iteration_mark (Type : CharFilter)
    日本語の々、ヽなどの踊り字をノーマライズ
  • kuromoji (Type : Analyzer)
    各種 tokenizer、fokenfilter を組合せるための analyzer
  • kuromoji_tokenizer (Type : Tokenizer)
    日本語のトークナイズモードの各種設定
  • kuromoji_baseform (Type : TokenFilter)
    日本語の動詞、形容詞を原型に変換
  • kuromoji_part_of_speech (Type : TokenFilter)
    日本語の各種品詞の除外
  • kuromoji_readingform (Type : TokenFilter)
    カタカナまたは、ローマ字読みに変換
  • kuromoji_stemmer (Type : TokenFilter)
    一般的なカタカナのスペルから長音記号を削除

CharFilter : kuromoji_iteration_mark

日本語の々、ヽ、ゝ などの踊り字をノーマライズするための CharFilter です。漢字と仮名の2種類のオプションがあります。

# 設定サンプル
# edit: $ES_HOME/config/elasticsearch.yml
index:
analysis:
char_filter:
kanji_iteration_mark:
type: kuromoji_iteration_mark
normalize_kanji: true
normalize_kana: false
kana_iteration_mark:
type: kuromoji_iteration_mark
normalize_kanji: false
normalize_kana: true
analyzer:
im_default:
tokenizer: standard
char_filter: [kuromoji_iteration_mark]
im_kanji_only:
tokenizer: standard
char_filter: [kanji_iteration_mark]
im_kana_only:
tokenizer: standard
char_filter: [kana_iteration_mark]

デフォルトと、漢字のみ、仮名のみのテスト用アナライザーを3つ用意しました。

Elasticsearch を再起動して確認してみます。

# 確認コマンド例: デフォルト
$ curl ‘localhost:9200/sample/_analyze?pretty=true&analyzer=im_default’ -d ‘ところゞゝゝ、ジヾが、時々、馬鹿々々しい’
# ところどころ、ジが、時、馬鹿馬鹿しい
# 確認コマンド例: 漢字のみ
$ curl ‘localhost:9200/sample/_analyze?pretty=true&analyzer=im_only_kanji’ -d ‘ところゞゝゝ、ジヾが、時々、馬鹿々々しい’
# ところゞゝゝ、ジヾが、時、馬鹿馬鹿しい
# 確認コマンド例: 仮名のみ
$ curl ‘localhost:9200/sample/_analyze?pretty=true&analyzer=im_only_kana’ -d ‘ところゞゝゝ、ジヾが、時々、馬鹿々々しい’
# ところゞゝゝ、ジが、時々、馬鹿々々しい

Tokenizer : kuromoji_tokenizer

日本語形態素解析用のトークナイザーです。形態素解析する為のモード、句読点の取扱い、ユーザー辞書による単語を制御します。

  • mode (default : search)
    normal / search / extended の3つのモードを提供。
  • discard_punctuation (default : true)
    句読点の取扱い。デフォルトは、句読点は除外されます。
  • user_dictionary
    ユーザー辞書ファイルのパスを設定します。
# 設定サンプル
# edit: $ES_HOME/config/elasticsearch.yml
index:
analysis:
tokenizer:
ja_tokenizer:
type: kuromoji_tokenizer
mode: search
analyzer:
ja:
type: custom
tokenizer: ja_tokenizer

search モードでトークナイズするだけのシンプルな設定例です。

Elasticsearch を再起動して確認してみます。

# 確認コマンド例
$ curl ‘localhost:9200/sample/_analyze?pretty=true&analyzer=ja’ -d ‘東京スカイツリー’
# 東京/スカイ/ツリー

形態素解析のモード

次の3つのモードが提供されています。

mode : normal
このモードは、単語は分割されません。
“関西国際空港” ⇒ “関西国際空港”
“アブラカタブラ” ⇒ “アブラカタブラ”
mode : search
このモードは、最小単位の単語の分割された単語と同義語として長い単語の両方を含みます。
“関西国際空港” ⇒ “関西” “関西国際空港” “国際” “空港”
“アブラカタブラ” ⇒ “アブラカタブラ”
mode : extended
このモードは、未知の単語をユニグラム(1文字単位)に分割します。
“関西国際空港” ⇒ “関西” “国際” “空港”
“アブラカタブラ” ⇒ “ア” “ブ” “ラ” “カ” “タ” “ブ” “ラ”

ユーザー辞書

kuromoji トークナイザーは、Mecab-IPADIC 辞書をデフォルトで使用しています。kuromoji はユーザー辞書を定義することができます。

ユーザー辞書は、次のCSVフォーマットに従って記述し、$ES_HOME/config ディレクトリ配下に保存したファイル名を user_dict に設定し使用します。

# CSV フォーマット:
<text>,<token 1> … <token n>,<reading 1> … <reading n>,<part-of-speech tag>
# ユーザー辞書例:
# edit: $ES_HOME/config/userdict_ja.txt
東京スカイツリー,東京 スカイツリー,トウキョウ スカイツリー,カスタム名詞
# 設定サンプル
# edit: $ES_HOME/config/elasticsearch.yml
index:
analysis:
tokenizer:
ja_tokenizer:
type: kuromoji_tokenizer
mode: search
user_dictionary: userdict_ja.txt
analyzer:
ja:
type: custom
tokenizer: ja_tokenizer
# 確認コマンド例:
curl -XPOST ‘http://localhost:9200/sample/_analyze?analyzer=ja&pretty' -d ‘東京スカイツリー’
# 東京/スカイツリー

TokenFilter : kuromoji_baseform

このフィルターは、動詞と形容詞を原型に変換するためのフィルターです。例えば、”飲み放題” と言う単語を”飲む”でもマッチさせたい場合に使用します。

# 設定サンプル
# edit: $ES_HOME/config/elasticsearch.yml
index:
analysis:
tokenizer:
ja_tokenizer:
type: kuromoji_tokenizer
mode: search
analyzer:
ja:
type: custom
tokenizer: ja_tokenizer
filter: [kuromoji_baseform]
# 確認コマンド例
$ curl -XPOST ‘http://localhost:9200/sample/_analyze?analyzer=ja&pretty' -d ‘飲み放題’
# 飲む/放題 ※ “飲み”が原型の”飲む”に変換されます。

TokenFilter : kuromoji_part_of_speech

このフィルターは指定された品詞を除外するためのフィルターです。

NOTE:
デフォルトは、lucene-analyzer-kuromoji.jar に含まれる stoptags.txt に設定されている品詞が除外されます。※ 特殊な場合をのぞいてデフォルトのままで良さそうです。

—- stoptags.txt のデフォルト除外品詞 —-
接続詞
e.g. が, けれども, そして, じゃあ, それどころか
助詞
助詞-格助詞
助詞-格助詞-一般 e.g. から, が, で, と, に, へ, より, を, の, にて
助詞-格助詞-引用 e.g. ( だ) と (述べた.), ( である) と (して執行猶予…)
助詞-格助詞-連語 e.g. という, といった, とかいう, として, とともに, …
助詞-接続助詞 e.g. から, からには, が, けれど, けれども, けど, し, つつ, …
助詞-係助詞 e.g. こそ, さえ, しか, すら, は, も, ぞ
助詞-副助詞 e.g. がてら, かも, くらい, 位, ぐらい, しも, …
助詞-間投助詞 e.g. (松島) や
助詞-並立助詞 e.g. と, たり, だの, だり, とか, なり, や, やら
助詞-終助詞 e.g. かい, かしら, さ, ぜ, (だ)っけ-口語/, (とまってる) で-方言/
助詞-副助詞/並立助詞/終助詞 e.g. か
助詞-連体化
助詞-副詞化
e.g. に, と
助詞-特殊 e.g. かな, けむ, ( しただろう) に, (あんた) にゃ(わからん), …
助動詞
記号
記号-一般
e.g. [○◎@$〒→+]
記号-読点 e.g. [,、]
記号-句点 e.g. [..。]
記号-空白
記号-括弧開 e.g. [({‘“『【]
記号-括弧閉 e.g. [)}’”』」】]
その他-間投 e.g. (だ)ァ
フィラー e.g. あの, うんと, えと
非言語音

個別に設定するには、次のようにします。

# 設定サンプル: 助詞-格助詞-一般、助詞-終助詞 を除外
index:
analysis:
filter:
pos_filter:
type: kuromoji_part_of_speech
stoptags: [助詞-格助詞-一般, 助詞-終助詞]
tokenizer:
ja_tokenizer:
type: kuromoji_tokenizer
mode: search
analyzer:
ja:
type: custom
tokenizer: ja_tokenizer
filter: [pos_filter]
# 確認コマンド例
$ curl -XPOST ‘http://localhost:9200/sample/_analyze?analyzer=ja&pretty' -d ‘寿司がおいしいね’
# 寿司/おいしい ※ “が”、”ね” が削除されます。

TokenFilter : kuromoji_readingform

このフィルターは、カタカナまたはローマ字の読みに変換するためのフィルターです。デフォルトはカタカナです。

# 設定サンプル
# edit: $ES_HOME/config/elasticsearch.yml
index:
analysis:
filter:
romaji:
type: kuromoji_readingform
use_romaji: true
katakana:
type: kuromoji_readingform
use_romaji: false
tokenizer:
ja_tokenizer:
type: kuromoji_tokenizer
mode: search
analyzer:
romaji_ja:
type: custom
tokenizer: ja_tokenizer
filter: [romaji]
katakana_ja:
type: custom
tokenizer: ja_tokenizer
filter: [katakana]
# 確認コマンド例:ローマ字
$ curl ‘localhost:9200/sample/_analyze?pretty=true&analyzer=romaji_ja’ -d ‘寿司’
# sushi ※ ローマ字に変換されます。
# 確認コマンド例:カタカナ
curl ‘localhost:9200/sample/_analyze?pretty=true&analyzer=katakana_ja’ -d ‘寿司’
# スシ ※ カタカナに変換されます。

TokenFilter : kuromoji_stemmer

このフィルターは、一般的なカタカナのスペルから最後の長音記号を削除するためのフィルターです。minimum_length (default : 4)の文字数を超える単語に適用されます。

# 設定サンプル
# edit: $ES_HOME/config/elasticsearch.yml
index:
analysis:
filter:
katakana_stemmer:
type: kuromoji_stemmer
minimum_length: 4
tokenizer:
ja_tokenizer:
type: kuromoji_tokenizer
mode: search
analyzer:
ja:
type: custom
tokenizer: ja_tokenizer
filter: [katakana_stemmer]
# 確認コマンド例:minimum_length 未満
$ curl ‘localhost:9200/sample/_analyze?pretty=true&analyzer=ja’ -d ‘コピー’
# コピー ※ 長音は削除されません。
# 確認コマンド例:minimum_length 以上
$ curl ‘localhost:9200/sample/_analyze?pretty=true&analyzer=ja’ -d ‘サーバー’
# サーバ ※ 最後の長音が削除されます。

cjk_width Token Filter

ckk_width は Elasticsearch にバンドルされている、全角記号を半角に統一したり、全角英数字を半角に統一したり、半角カタカナを全角に統一する為のフィルターです。

# 設定サンプル
# edit: $ES_HOME/config/elasticsearch.yml
index:
analysis:
analyzer:
normalize:
tokenizer: whitespace
filter: [cjk_width]
# 確認コマンド例
$ curl ‘localhost:9200/sample/_analyze?pretty=true&analyzer=normalize’ -d ‘フガホゲ-%*@ABC−%*@123'
# フガホゲ-%*@ABC−%*@123

こういう言語に依存しないノーマライズ系のフィルターは、トークナイズ前の char_filter で処理できれば良いのですが、誰か別のフィルターご存じないですか?

NOTE:
類似の処理を提供する
ICU Analysis for Elasticsearch プラグインにふくまれる icu_normalizer があります。

Lowercase Token Filter

英字の大文字を小文字に変換する為のフィルターです。Elasticsearch にバンドルされています。

# 設定サンプル
index:
analysis:
analyzer:
lowercase:
tokenizer: whitespace
filter: [lowercase]
# 確認コマンド例
$ curl ‘localhost:9200/sample/_analyze?pretty=true&analyzer=lowercase’ -d ‘ABC’
# abc ※ 小文字に変換されます。

Synonym Token Filter

同義語を展開する為のフィルターです。Elasticsearch にバンドルされています。

# 設定サンプル
# edit: $ES_HOME/config/elasticsearch.yml
index:
analysis:
filter:
synonym_dict:
type: synonym
synonyms_path: analysis/synonym.txt
analyzer:
synonym:
tokenizer: standard
filter: [synonym_dict]
# edit: $ES_HOME/config/analysis/synonym.txt
Tokyo, 東京, 首都圏
# 確認コマンド
$ curl ‘localhost:9200/sample/_analyze?pretty=true&analyzer=synonym’ -d ‘Tokyo’
# Tokyo, 首都圏, 東京 ※ 辞書の内容で同義語が展開されます。

NOTE:
Synonym Token Filter を日本語と一緒に使用する場合は、辞書の内容もトークナイザーの仕様にあわせて単語を分割して登録しておく必要があります。
○:tokyo, 首都␣圏, 東京␣都 ※ ␣は半角スペース
×:tokyo, 首都圏, 東京都

STOP Token Filter

任意の単語を除外する為のフィルターです。Elasticsearch にバンドルさています。

# 設定サンプル
# edit: $ES_HOME/config/elasticsearch.yml
index:
analysis:
stopword_dict:
type: stop
stopwords_path: analysis/stopword.txt
analyzer:
stopword:
tokenizer: standard
filter: [lowercase, stopword_dict]
# edit: $ES_HOME/config/analysis/stopword.txt
tokyo
# 確認コマンド例
$ curl ‘localhost:9200/sample/_analyze?pretty=true&analyzer=stopword’ -d ‘Tokyo Osaka’
# osaka ※ tokyo が削除されます。

NOTE:
日本語で Stop Token Filter を使用する場合は、トークナイザーで分割された最小単位の単語を除外ワードとして登録可能です。例えば、”東京都”と言う単語を除外したい場合は、”東京” と “都” をそれぞれ登録する必要があります。この場合、”東京ディズニーランド” などのキーワードも、”東京”が除外されますので、登録には注意が必要です。

次回は、これらのモジュールを組み合わせて、日本語全文検索の為のアナライザーの設定を考えてみたいと思います。

--

--