elasticsearchelasticsearch-mappingelasticsearch-template

Elasticsearch dynamic template: don’t want field to be analyzed, only want a keyword subfield


We're using a dynamic template to specify mapping for certain fields in our index. Most text fields are not mentioned in the template, and get the default mapping to an analyzed field and a keyword subfield:

                      "someField" : {
                        "type" : "text",
                        "fields" : {
                          "keyword" : {
                            "type" : "keyword"
                          }
                        }
                      }

which is good.

The index has some fields that we don't want to be analyzed, just made keywords. However, for consistency, we want all keyword fields to be a subfield named "keyword", like the above. So this:

"dynamic_templates" : [

  {
    "someField" : {
      "match" : "someField",
      "mapping" : {
        "type" : "keyword",
        "norms" : false
      }
    }
  },

isn't suitable, as it makes "someField" itself a keyword, and we want "someField.keyword" to be the keyword field. But if I use this template:

"dynamic_templates" : [

  {
    "someField" : {
      "match" : "someField",
      "mapping" : {
        "fields": {
          "keyword": {
            "type": "keyword",
            "norms" : false
          }
        }
      }
    }
  },

an analyzed "top-level" field is created as well as the keyword subfield:

                          "someField" : {
                            "type" : "text",
                            "fields" : {
                              "keyword" : {
                                "type" : "keyword"
                              }
                            }
                          },

Is there a way to not have the "someField" field mapped, only "someField.keyword"? I could set index : false for the "someField" level, but users may still try to use it, and wonder why it's not working.

EDIT: I have tried to define someField as an object type, as suggested by haltabush, but get an error. Using this template:

{
  "template": "test*",
  "order":    1,

    "mappings" : {
      "_default_" : {

        "dynamic_templates" : [
          {
            "someField" : {
              "match" : "someField",
              "mapping" : {
                "type" : "object",
                "fields": {
                  "keyword": {
                    "type": "keyword"
                  }
                }
              }
            }
          }
        ]
      }
    }
}

When I post this document:

curl -XPUT localhost:9200/test-1/doc/1?pretty -d '
{
  "someField" : "some value"
}
'

I get this error:

{
  "error" : {
    "root_cause" : [
      {
        "type" : "mapper_parsing_exception",
        "reason" : "object mapping for [someField] tried to parse field [someField] as object, but found a concrete value"
      }
    ],
    "type" : "mapper_parsing_exception",
    "reason" : "object mapping for [someField] tried to parse field [someField] as object, but found a concrete value"
  },
  "status" : 400
}

Solution

  • You can create an object:

                         "someField" : {
                            "type" : "object",
                            "fields" : {
                              "keyword" : {
                                "type" : "keyword"
                              }
                            }
                          },