読者です 読者をやめる 読者になる 読者になる

DRYな備忘録

Don't Repeat Yourself.

No mapping found for [hoge] in order to sort on【Elasticsearch】

elasticsearch

ビジネス的要件からソートロジックの変更に伴って、hogeという新しいフィールドでソートしたいので、以下を投げたら、掲題のエラーを食らった。

curl ":9200/foo/bar/_search?size=2&pretty" -d '{"sort":[{"hoge":"desc"}]}'

叱られている通り、hogeというフィールドに対するmappingが無いんですって。

Mapping

mappingはドキュメントがサーチエンジンに対してどのようにマップされるかを定義します。ドキュメントが検索可能なフィールドを含むときは、そのフィールドについても、どのようにトークナイズしてマップするかも定義します。Elasticsearchでは、ひとつのindexはドキュメントを独立した"mapping type"に保存します。ひとつのインデックスに対して複数の異なるmapping typeをヒモづけることも可能です。*1

なんのこっちゃ

mappingは'index/type'単位で定義されます。新しいtypeや新しいfieldを追加したとき、自動的にmappingが追加されるので、明示的に定義する必要はありません。デフォルトでつくられたmappingを上書きしたいときだけ、mappingの定義を明示しなければなりません。*2

hogeフィールド足すと、自動的にmappingが更新される??

まずはドキュメントひとつ取得してみる

curl ":9200/foo/bar/54e5a8788bd2c75c66bc3983?pretty=true"

{
  "_index" : "foo",
  "_type" : "bar",
  "_id" : "54e5a8788bd2c75c66bc3983",
  "_version" : 1,
  "found" : true,
  "_source":{"title":"おっぱい", "description": "This is description"}
}

検索してみる

curl ":9200/foo/bar/_search?pretty=1" -d '{"query":{"match":{"description":{"query":"This"}}}}'

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 5.4485164,
    "hits" : [ {
      "_index" : "foo",
      "_type" : "bar",
      "_id" : "54e5a8788bd2c75c66bc3983",
      "_score" : 5.4485164,
      "_source":{"title":"おっぱい", "description": "This is description"}
    } ]
  }
}

mappingsの確認

curl ":9200/foo/_mappings?pretty"

{
  "foo" : {// fooインデックスの
    "mappings" : {
      "bar" : {// barタイプに定義されているmappings
        "properties" : {
          "description" : {
            "type" : "string"
          },
          "title" : {
            "type" : "string"
          }
        }
      }
    }
  }
}

フィールドを追加してみる

curl -XPOST ":9200/foo/bar/54e5a8788bd2c75c66bc3983/_update?pretty=1" -d '{"script": "ctx._source.hoge = 100"}'

{
  "_index":"foo",
  "_type":"bar",
  "_id":"54e5a8788bd2c75c66bc3983",
  "_version":2
}

そしてもう一回mappingsを確認

curl ":9200/foo/_mappings?pretty"

{
  "foo" : {// fooインデックスの
    "mappings" : {
      "bar" : {// barタイプに定義されているmappings
        "properties" : {
          "description" : {
            "type" : "string"
          },
          "hoge": { // フィールドが追加され自動的にmappingsが追加されてる!
            "type": "long"
          },
          "title" : {
            "type" : "string"
          }
        }
      }
    }
  }
}

追加されとるやん!

ということで、冒頭の_searchをもう一度投げてみる

curl ":9200/foo/bar/_search?size=2&pretty" -d '{"sort":[{"hoge":"desc"}]}'

{
  "took" : 7,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
// 以下略

成功した!

結論

  • No mapping found for [hoge] in order to sort on は、index/typeのmappingsにhogeが無いことによるエラー
  • 特定のフィールドのmappingsの追加は、フィールドの新規追加に伴って自動的に行われる

DRY

*1:Mapping is the process of defining how a document should be mapped to the Search Engine, including its searchable characteristics such as which fields are searchable and if/how they are tokenized. In Elasticsearch, an index may store documents of different "mapping types". Elasticsearch allows one to associate multiple mapping definitions for each mapping type.

*2:Explicit mapping is defined on an index/type level. By default, there isn’t a need to define an explicit mapping, since one is automatically created and registered when a new type or new field is introduced (with no performance overhead) and have sensible defaults. Only when the defaults need to be overridden must a mapping definition be provided.