Search code examples
spring-bootelasticsearchspring-data-elasticsearch

Keyword field created automatically without any mapping in Entity class


My ElasticSearch version is 7.6.2 and my spring-boot-starter-data-elasticsearch is version 2.2.0. Due to some dependency i am not upgrading ES to lastest version. Problem i am facing is ES index is sometimes created with .keyword fields and sometimes it is just normal text field. Below is my entity class. i am not able to find why this is happening. I read that all text field will have keyword field also. but why it is not created always.

My Entity class

@Setter
@Getter
@Document(indexName="myindex", createIndex=true, shards = 4)
public class MyIndex { 

    @Field(type = FieldType.Keyword)
     private String place;  
    @Field(type = FieldType.Text)
     private String name;       
    @Id 
    private String dynamicId = UUID.randomUUID().toString();

    public MyIndex()
    {}

Mapping in ES:

{
  "mappings": {
    "myindex": {
      "properties": {
        "place": {
          "type": "text",
          "fields": {
            "keyword": {
              "ignore_above": 256,
              "type": "keyword"
            }
          }
        },
        "name": {
          "type": "text",
          "fields": {
            "keyword": {
              "ignore_above": 256,
              "type": "keyword"
            }
          }
        },
        "dynamicId": {
          "type": "text",
          "fields": {
            "keyword": {
              "ignore_above": 256,
              "type": "keyword"
            }
          }
        }
      }
    }
  }
}

Sometimes it is created as below for the same entity class

{
  "mappings": {
    "myindex": {
      "properties": {
        "place": {
          "type": "keyword"
        },
        "name": {
          "type": "text"
        },
        "dynamicId": {
          "type": "text",
          "fields": {
            "keyword": {
              "ignore_above": 256,
              "type": "keyword"
            }
          }
        }
      }
    }
  }
}

Solution

  • With the entity definition shown, when Spring Data Elasticsearch creates the index and writes the mapping, you will get the mapping shown in your second example with these value for the properties:

    {
      "properties": {
        "place": {
          "type": "keyword"
        },
        "name": {
          "type": "text"
        }
      }
    }
    

    If you want to have a nested keyword property in Spring Data Elasticsearch you have to define it on the entity with the corresponding annotation.

    Please notice: the @Id property is not mapped explicitly but will be dynamically mapped on first indexing of a document.

    The mapping in the first case and the part in the second where a String is mapped as

      "type": "text",
      "fields": {
        "keyword": {
          "ignore_above": 256,
          "type": "keyword"
        }
      }
    }
    

    is the default value that Elasticsearch uses when a document is indexed with a text field that was not mapped before - see the docs about dynamic mapping.

    So your second example shows the mapping of an index that was created by Spring Data Elasticsearch and where some documents have been indexed.

    The first one would be created by Elasticsearch if some other application creates the index and writes data into the index. It could also be that the index was created outside your application, and on application startup no mapping would then be written, because the index already exists. So you should review the way your indices are created.