ElasticSearch でインデックス時と全文検索時で異なる analyzer を設定する
前回はElasticSearch
が全文検索クエリを処理する際の分かち書きのしくみについてふれました。ElasticSearch
ではさまざまな種類の tokenizer
を中心に analyzer
を設計することができ、この analyzer
が実際に文字列の単語分割を行ってくれます。ElasticSearch
ではインデックスに格納するドキュメントの内容(フィールドの値)と、全文検索クエリの検索キーワードに対して分かち書きが行われますが、この 2 つに対して異なる analyzer
を適用することができます。今回は、インデックスにドキュメントを格納する際の転値インデックス作成時と、検索キーワードを渡した全文検索クエリでの検索時とで、異なる analyzer
を利用してみたいと思います。インデックス時と全文検索時の analyzer の単語分割結果を確認する
ElasticSearch
では、インデックスにドキュメントを格納する際の転値インデックス作成時に適応される analyzer
と、全文検索クエリで渡される検索キーワードに適用される analyzer
を設定できます。となるとインデックス時と全文検索時に動作している analyzer
の処理結果をそれぞれ確認したいということになると思います。まずはじめにこれらの分かち書きの結果を確認する方法についてみておきます。以下のインデックスを材料に、まずは 2 種類の
analyzer
の動作確認をしてみます。$ curl -XPUT http://localhost:9200/analyzer-sample01 -H "Content-type: application/json" -d '{ "settings": { "analysis": { "analyzer": { "my_whitespace_analyzer": { "tokenizer": "whitespace" } } } }, "mappings": { "_doc": { "properties": { "my_field01": { "type": "text", "analyzer": "my_whitespace_analyzer" } } } } }'
インデックス時の analyzer の単語分割結果を確認する
インデックスにドキュメントを格納する際の転値インデックス作成時に適応されるanalyzer
が、実際にどのように分かち書きを行うか確認してみます。インデックス時の
analyzer
の動作は、前回も利用した Analyze API から確認できます。/{インデックス名}/_analyze
エンドポイントに、field
値にフィールドの名前を、text
値にフィールドに格納する値を指定した JSON を POST します。そうすると、そのフィールドにそのフィールド値を格納した場合に analyzer
が行う単語分割の結果が返されてきます。この時、存在しないフィールドを指定してしまうと、
Standard Tokenizer
が設定されたデフォルトの analyzer
によって分かち書きされてしまうので注意してください。$ curl -XPOST http://localhost:9200/analyzer-sample01/_analyze -H "Content-type: application/json" -d '{ "field": "my_field01", "text": "ひさかたの 光のどけき 春の日に" }'
my_field01
フィールドには、Whitespace Tokenizer
の設定された analyzer
が指定されているため、このフィールドに値『ひさかたの 光のどけき 春の日に』をインデックスしようとすると、『ひさかたの』『光のどけき』『春の日に』の 3 単語に分かち書きが行われるはずです。こちらが実行結果です。
{ "tokens": [ { "token": "ひさかたの", "start_offset": 0, "end_offset": 5, "type": "word", "position": 0 }, { "token": "光のどけき", "start_offset": 6, "end_offset": 11, "type": "word", "position": 1 }, { "token": "春の日に", "start_offset": 12, "end_offset": 16, "type": "word", "position": 2 } ] }
Whitespace Tokenizer
によって分かち書きされた結果が返ってきました。全文検索時の analyzer の単語分割結果を確認する
全文検索クエリで渡される検索キーワードに適用されるanalyzer
が、実際にどのように分かち書きを行うか確認してみます。全文検索時の
analyzer
の動作は、Validate API から確認できます。Validate API 自体は全文検索クエリに間違いがないかを確認するためのものですが、レスポンスには analyzer
による単語分割の結果も含まれています。利用する Validate API のエンドポイントは
/{インデックス名}/_validate/query?explain
です。送信する JSON オブジェクトの内容は、全文検索クエリで実際に送るものと同じです。$ curl -XGET http://localhost:9200/analyzer-sample01/_validate/query?explain -H "Content-type: application/json" -d '{ "query": { "match" : { "my_field01" : "しづ心なく 花の散るらむ" } } }'
my_field01
フィールドには、Whitespace Tokenizer
の設定された analyzer
が指定されているため、このフィールドに対して検索キーワード『しづ心なく 花の散るらむ』で全文検索しようとすると、検索キーワードは『しづ心なく』『花の散るらむ』の 2 単語に分かち書きが行われるはずです。{ "_shards": { "total": 1, "successful": 1, "failed": 0 }, "valid": true, "explanations": [ { "index": "analyzer-sample01", "valid": true, "explanation": "my_field01:しづ心なく my_field01:花の散るらむ" } ] }
explanations.explanation
値に、analyzer
が検索キーワードを単語分割した結果が格納されます。スペース区切りで 2 単語返されていますね。仮に
analyzer
が Keyword Tokenizer
で単語分割したとすると、Keyword Tokenizer
はスペースでは単語を分割しないので、my_field01:しづ心なく 花の散るらむ
という結果が返ってきます。インデックス時と全文検索時で異なる analyzer を設定する
それでは、転移インデックス作成時と全文検索クエリでの検索時とで適応されるanalyzer
を変えてみます。フィールドに
search_analyzer
を設定すると、全文検索時の検索キーワードに対してはその analyzer
が使用されるようになります。search_analyzer
の設定が適用されるのは全文検索時のみで、インデックス時の analyzer
には影響がありません。つまり、フィールドの analyzer
値と search_analyzer
値に異なる analyzer
を設定することで、ドキュメントの内容と検索キーワードに対して別々の分かち書きを行うことができます。フィールドに
search_analyzer
を設定しないなら、これまで見てきたとおり、全文検索時には analyzer
値に設定したものが使用されます。以下のインデックスでは、インデックス時には
Whitespace Tokenizer
が、全文検索時には Keyword Tokenizer
が動作することになります。$ curl -XPUT http://localhost:9200/analyzer-sample02 -H "Content-type: application/json" -d '{ "settings": { "analysis": { "analyzer": { "my_whitespace_analyzer": { "tokenizer": "whitespace" }, "my_keyword_analyzer": { "tokenizer": "keyword" } } } }, "mappings": { "_doc": { "properties": { "my_field02": { "type": "text", "analyzer": "my_whitespace_analyzer", "search_analyzer": "my_keyword_analyzer" } } } } }'
実際にインデックス時の
analyzer
の動きを確認してみます。確認したいフィールドを指定して Analyze API にリクエストします。$ curl -XPOST http://localhost:9200/analyzer-sample02/_analyze -H "Content-type: application/json" -d '{ "field": "my_field02", "text": "ちはやぶる 神代もきかず 竜田川 からくれなゐに 水くくるとは" }'インデックス時の
analyzer
による分かち書き結果は以下の通りです。{ "tokens": [ { "token": "ちはやぶる", "start_offset": 0, "end_offset": 5, "type": "word", "position": 0 }, { "token": "神代もきかず", "start_offset": 6, "end_offset": 12, "type": "word", "position": 1 }, { "token": "竜田川", "start_offset": 13, "end_offset": 16, "type": "word", "position": 2 }, { "token": "からくれなゐに", "start_offset": 17, "end_offset": 24, "type": "word", "position": 3 }, { "token": "水くくるとは", "start_offset": 25, "end_offset": 31, "type": "word", "position": 4 } ] }
Whitespace Tokenizer
によってスペース毎に分かち書きされました。続いて全文検索時の
analyzer
の動きを確認してみます。確認したい全文検索クエリを指定して、Validate API にリクエストします。$ curl -XGET http://localhost:9200/analyzer-sample02/_validate/query?explain -H "Content-type: application/json" -d '{ "query": { "match" : { "my_field02" : "ちはやぶる 神代もきかず 竜田川 からくれなゐに 水くくるとは" } } }'全文検索時の
analyzer
による分かち書き結果は以下の通りです。{ "_shards": { "total": 1, "successful": 1, "failed": 0 }, "valid": true, "explanations": [ { "index": "analyzer-sample02", "valid": true, "explanation": "my_field02:ちはやぶる 神代もきかず 竜田川 からくれなゐに 水くくるとは" } ] }
Keyword Tokenizer
が動作しているため、検索キーワードがそのまま 1 単語として分かち書きされました。ここまでで、フィールドの
analyzer
値と search_analyzer
値を変えることで、インデックス時と全文検索時で異なる analyzer
を指定できることを見てきました。ElasticSearch
の古いバージョンでは、フィールドに対して index_analyzer
値を指定することで、明示的にインデックス時のみ適用される analyzer
を設定できていましたが、最近のバージョンでは index_analyzer は廃止された そうです。基本的には analyzer
値を指定し、全文検索時の分かち書き方法を変更したい場合にのみ search_analyzer
を指定する、というほうが仕様としてはシンプルでいいと思います。インデックス時と全文検索時で異なるデフォルト analyzer を設定する
さきほどの例ではフィールドに対して個別にインデックス用analyzer
と全文検索用 analyzer
を指定しましたが、ドキュメントタイプに対するデフォルトの analyzer
についてもインデックス時と全文検索時とで異なる analyzer
を設定することができます。マッピングの
settings
配下の default
値には、このマッピング内の全フィールドに適用する analyzer
を指定することができます。この default
値は、これ単体だと、インデックス時と全文検索時の両方で利用され、また個別に analyzer
が指定されていないすべてのフィールドに適用されます。マッピングの
settings
配下には加えて default_search
値を設定することができます。これはこのマッピング内の全フィールドに適用される search_analyzer
に相当し、個別に search_analyzer
が指定されていないすべてのフィールドに適用されます。つまり、この
default
値と default_search
値に異なる analyzer
を設定することでも、ドキュメントの内容と検索キーワードに対して別々の分かち書きを行うことができます。以下のインデックスでは、フィールドに対しては
analyzer
の指定をしていませんが、フィールドのデフォルト設定として、インデックス時には Keyword Tokenizer
が、全文検索時には Whitespace Tokenizer
が動作するように指定しています。$ curl -XPUT http://localhost:9200/analyzer-sample03 -H "Content-type: application/json" -d '{ "settings": { "analysis": { "analyzer": { "default": { "tokenizer": "keyword" }, "default_search": { "tokenizer": "whitespace" } } } }, "mappings": { "_doc": { "properties": { "my_field03": { "type": "text" } } } } }'
実際にインデックス時の
analyzer
の動きを確認してみます。確認したいフィールドを指定して Analyze API にリクエストします。$ curl -XPOST http://localhost:9200/analyzer-sample03/_analyze -H "Content-type: application/json" -d '{ "field": "my_field03", "text": "月見れば ちぢにものこそ 悲しけれ わが身一つの 秋にはあらねど" }'インデックス時の
analyzer
による分かち書き結果は以下の通りです。{ "tokens": [ { "token": "月見れば ちぢにものこそ 悲しけれ わが身一つの 秋にはあらねど", "start_offset": 0, "end_offset": 32, "type": "word", "position": 0 } ] }デフォルトのインデックス用
analyzer
として Keyword Tokenizer
が動作し、そのまま 1 単語として分かち書きされました。続いて全文検索時の
analyzer
の動きを確認してみます。確認したい全文検索クエリを指定して、Validate API にリクエストします。$ curl -XGET http://localhost:9200/analyzer-sample03/_validate/query?explain -H "Content-type: application/json" -d '{ "query": { "match" : { "my_field03" : "月見れば ちぢにものこそ 悲しけれ わが身一つの 秋にはあらねど" } } }'全文検索時の
analyzer
による分かち書き結果は以下の通りです。{ "_shards": { "total": 1, "successful": 1, "failed": 0 }, "valid": true, "explanations": [ { "index": "analyzer-sample03", "valid": true, "explanation": "my_field03:月見れば my_field03:ちぢにものこそ my_field03:悲しけれ my_field03:わが身一つの my_field03:秋にはあらねど" } ] }デフォルトの検索用
analyzer
として Whitespace Tokenizer
が動作しているため、検索キーワードが 5 つの単語に分かち書きされました。古いバージョンの
ElasticSearch
では、マッピング内に default_index
値を指定することで、すべてのフィールドに対してデフォルトのインデックス用 analyzer
を指定できました。しかし、これもフィールドに設定する index_analyzer
値と同じように、現在では廃止されています。ElasticSearch コメント (1) 2018/10/12 17:43:15