【入門】 ElasticsearchのAnalyzer周辺の知識をまとめた

2021-04-18

はじめに

今回の記事ではElasticsearchの「Analyzer」「ユーザー辞書」「Synonym」「Analyzerのデバッグ」といった部分の解説をしていこうと思います。特に踏み入った話はするつもりはないのでその辺りはあらかじめご了承ください。

Elasticsearch: Analyzer

Analyzerとは

Analyzerはテキストの最適化処理を行うアリゴリズムのことです。ここでいう最適化処理というのはあるテキストをある用語に変換する処理のことを言っています。例えば「おすし」というテキストを「お寿司」に変換するといった感じです。

Analyzers are the special algorithms that determine how a string field in a document is transformed into terms in an inverted index

引用:「All About Analyzers, Part One

Analyzer内部の構成要素について

まず初めに分析対象のテキストに該当するデータは大まかに次の2種類に分類できます。

  • クライアント側から送られてくるデータ
  • DBに保存されているデータ

これらのデータを入力として、次の3つの処理によって最終的な出力になります。

  • Character Filter
  • Tokenizer
  • Token Filter

この3つの処理をまとめてAnalyzerと呼んでいます。これらの処理は次の図のフローで実行されます。

ではそれぞれを少し掘り下げてみていきましょう。

Character Filter

文字ストリーム(テキスト)に対して1番初めに処理を行う箇所であり、テキストの追加・削除・置換を行います。具体的な使われ方としては特定の禁止ワードだったら削除したり、表記揺れがあるテキストだったらもっとも標準的な用語に変換するといった使われ方をします。

Tokenizer

Character Filterが吐き出した文字ストリーム(テキスト)をtokenと呼ばれる単語に分割します。例えば「whitespace tokenizer」というTokenizerを使用すれwhitespace区切りでtokenに分割することができます。

input: "Quick brown fox!" 

whitespaceで各要素を区切ってtokenを配列形式で吐き出します。

output: [Quick, brown, fox!]

Token Filter

Tokennizerによって分割された個々のtokenに対して、テキストの追加・削除・置換を行うことができます。例えば「lowercase token filter」というToken Filterを使用した場合、すべてのtokenをlowercaseに変換されます。

Analyzerの設定方法

では次にAnalyzerの各処理を設定する方法について紹介します。Analyzerを設定するためにAnalyze APIというAPIを使用します。(余談ですがElasticsearchとのやりとりは基本的にAPI経由で行われます)Character filterを設定する場合、Analyze APIのPUTリクエストで次のようなJSONデータを送信します。(こちら公式ドキュメントに書かれていたものです)

PUT /my-index-000001 { "settings": { "analysis": { "analyzer": { "my_analyzer": { "tokenizer": "standard", "char_filter": [ "my_mappings_char_filter" ] } }, "char_filter": { "my_mappings_char_filter": { "type": "mapping", "mappings": [ ":) => happy", ":( => sad" ] } } } } }

my-index-000001はターゲットになるindexのことです。(名前は特に気にしないでください)my_mappings_char_filterというCharacter Filterをmy_analyzerのCharacter Filterに設定しています。これによってCharacter Filterの階層で:)happy, :(sadに変換されます。上の例ではmappingsに直接指定していますが、mappings_pathというキーに対して=>で書かれた.txtファイルのPathを記述することでも設定することもできます。(こちらの方がすっきり記述できるのでおすすめです)

Elasticsearch: user dictionary(ユーザー辞書)

user dictionary(ユーザー辞書)とは

user dictionary(ユーザー辞書)は数あるtokenizerの一種で以下の形式で.txtに記述することで定義することができます。

単語,形態素解析後の単語,読み,品詞

ユーザー辞書を使うと単語をどのように形態素解析するのかを自分で決めることができます。公式ドキュメントに載っていた例ですが userdict_ja.txtといった適当なテキストファイルを作成して、この中に次のように定義したとします。

// userdict_ja.txt 東京スカイツリー,東京 スカイツリー,トウキョウ スカイツリー,カスタム名詞

これによってTokenizer層で「東京スカイツリー」は「東京」「スカイツリー」のtokenに分割されるようになります。

user dictionary(ユーザー辞書)を設定する方法

上で紹介したユーザー辞書を設定するには次のようにTokenizerのuser_dictionaryのキーに対してユーザー辞書の形式で記述された.txtを指定して、hoge_user_dictというtokenizerを定義しています。このTokenizerをmy_analyzertokenizerに指定してあげれば良いです。

PUT kuromoji_sample { "settings": { "index": { "analysis": { "tokenizer": { “hoge_user_dict": { "type": "kuromoji_tokenizer", "mode": "extended", "discard_punctuation": "false", "user_dictionary": "userdict_ja.txt" } }, "analyzer": { "my_analyzer": { "type": "custom", "tokenizer": “hoge_user_dict" } } } } } }

これによってkuromoji_sampleというインデックスに対してユーザー辞書の機能を持つTokenizerを設定することができました。

Elasticsearch: Synonym

Synonymについて

SynonymはToken Filterの1種で正式名称は「synonym token filter」というようです。tokenの同義語を登録することで、Token Filter層で該当する同義語があればtokenを追加します。設定方法としては次のようにsynonyms_pathに同義語が定義されたsynonym.txtファイル(後で紹介)を登録して、それをanalyzerのtoken filter (filter)に記述します。

PUT /test_index { "settings": { "index": { "analysis": { "analyzer": { "synonym": { "tokenizer": "whitespace", "filter": [ "synonym" ] } }, "filter": { "synonym": { "type": "synonym", "synonyms_path": "analysis/synonym.txt" } } } } } }

synonym.txtの記述方法としては次のように

// analysis/synonym.txt ipod, i-pod, i pod

,で区切って単語設定します。1行毎に同義語のセットを登録してく感じです。これによってToken Filterで「ipod」というtokenは「i-pod」「i pod」を合わせた3つのtokenに変換されます。他にも細かいsynonym.txtの設定方法がありますが今回の記事では省略します。

Analyzerのデバッグ方法

Analyzerのデバッグするには上で紹介したAnalyzer APIを使用します。

Character Filterの場合

analyzerのCharacter Filtersに設定しているhtml_stripが意図した通りに文字ストリームを変換しているのかを確認したい場合、次のリクエストを含んだAnalyze APIを叩けば良いです。

curl -XPOST 'localhost:9200/_analyze?pretty' -H 'Content-Type: application/json' -d '{ "tokenizer": "standard", "char_filter": [ "html_strip" ], "text": "The <b> Auto-generation </b> is a success" }'

RDMSでいう実行計画のようなものでinputの文字ストリームがどのように変換されるのかを確認することができます。ちなみにhtml_stripはHTMLの要素をテキストに変換してくれるCharacter Filterです。処理の内容としましては「The <b> Auto-generation </b> is a success」というHTMLの文字列をhtml_stripで通常の文字列に変換した後、standard tokenizerによって文字列を各単語に分割します。上のAnalyzer APIの結果は次のようになります。

“The”,”Auto”,”generation”,”is”,”a”,”success”

Tokenizerの場合

analyzerのtokenizerに設定しているstandardがどのように単語を分割するのかを確認したい場合、次のAnalyze APIを叩いてデバッグすればよいです。

$ curl -XPOST ‘localhost:9200/_analyze?pretty’ -H ‘Content-Type: application/json’ -d '{ “tokenizer”: “standard”, “text”: “The Auto-generation is a success” }'

これにより「The Auto-generation is a success」がどのように分割されるのかを確認することができます。上のAPIリクエストの結果は次のようになります。

“The”,”Auto”,”generation”,”is”,”a”,”success”

各英単語がstandard tokenizerによって正しく分割できていることが確認できます。

Token Filterの場合

Token Filterのlowercaseがどのようにtokenを置換するのかを確認するには次のリクエストを含んだAnalyzer APIを叩けば良いです。

$ curl -XPOST 'localhost:9200/_analyze?pretty' -H 'Content-Type: application/json' -d'{ "tokenizer": "standard", "filter": [ "lowercase" ], "text": "The Auto-generation is a success" }'

この出力結果は次のようになります。

“the”,”auto”,”generation”,”is”,”a”,”success”

standard tokenizerによって分割された各tokenがToken Filterのlowercaseによって全て小文字に変換されていることが確認できました。

おわりに

といった感じで「Analyzer」「ユーザー辞書」「Synonym」「Analyzerのデバッグ」についてざっと解説しました。この記事が役に立てたらすごく嬉しいです。また何か新しい情報が入ってきたら記事を更新したいと思います。最後までお読みいただきありがとうございました。

参考文献:

KATUO
Software Engineer