Elasticsearch でつまづいた話 (1)

一人で Advent Calendar をやる。

テーマは決めてない。技術か音楽の話が大半になりそうだ。


いまのプロジェクトで Elasticsearch を使っている。そのなかで、知ってたらそりゃ当然なんだけど、はじめ概念として理解できなかったことが色々あったのでまとめてみる。タイトルに (1) とつけたが、続くかどうかは未定だ。

なお私が Elasticsearch の仕様と Lucene の仕様を混同している可能性がある。

Elasticsearch の概要

Elasticsaerch は全文検索エンジンであり、基本的に REST API によって利用する。

ドキュメントが大量にあっても高速に検索できることが特徴のひとつだ。

今回のつまづいた話

Elasticsearch はデータを保存する際、必ずしも入力された文字列をそのまま保存しない。フィールドに tokenizer/analyzer が指定でき、例えば日本語用のものを使えば文章を形態素解析して保存したりできる。

ここで注意したいのが、 token に分割されたフィールドはもとの文字列がもはや保存されていないということだ。つまり、「お待ちしております」が「お,待ち,し,て,おり,ます」と分割されたら、完全一致検索 (term query) で「お待ちしております」で検索しようとしてもヒットしないことになる。これは aggregation なども同様の問題が起こり、集約のキーにしたいのに分割された文字列がキーになってしまったりする。

文章だと完全一致で検索したいことは少ないかもしれないが、名称で検索する場合は、表記ゆれも tokenizer/analyzer で吸収したいし完全一致でも検索したい、ということが結構ある。

ここで登場するのが Multi Field だ。これをスキーマ定義に指定すると、ひとつのフィールドに入力された文字列が複数の方式で analyze される。 たとえば↓のように定義されていると、 hoge.piyo を用いると tokenize されたフィールド (text) が利用でき、 hoge.poyo を用いると tokenize されないフィールド (keyword) が利用できる。

"hoge": {
  "type": "multi_field",
  "fields": {
    "piyo": {
      "type": "text"
    },
    "poyo": {
      "type": "keyword"
    }
  }
}

また↓のようにも定義できる。この場合は hoge で text、 hoge.fuga で keyword が利用できる。Elasticsearch 5.0 以降では自動でこのマッピングが生成されるらしい。

"hoge": {
  "type": "text",
  "fields": {
    "fuga": {
      "type": "keyword"
    }
  }
}

hoge で定義したフィールドに対して更に下のフィールドを利用する、というイメージが当初全然理解できなかったというのがつまづきポイントであった。