19
votes

When using spring-data to insert Elasticsearch document with Date type, I can't get right date format, the date format always is Long.

here is the java code: Entity.java

import java.util.Date;

import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldIndex;
import org.springframework.data.elasticsearch.annotations.FieldType;

import com.fasterxml.jackson.annotation.JsonProperty;

@Document(indexName = "entity-index", type = "entity-type")
public class Entity {
    @Id
    private String id;

    @Field(type = FieldType.Date, index = FieldIndex.not_analyzed, store = true, 
            format = DateFormat.custom, pattern = "yyyy-MM-dd'T'hh:mm:ss.SSS'Z'")
    private Date createDate;

    private String system;
    private double score;

    @Field(type = FieldType.Date, format = DateFormat.date_optional_time)
    @JsonProperty(value = "@timestamp")
    private Date updateDate;
    // omit setter and getter 
}

Here is the Test

public class EntityDAOTest {
    @Autowired
    private ElasticsearchTemplate template;

    @Before
    public void init() {
        template.createIndex(Entity.class);
        template.putMapping(Entity.class);
    }


    @Test
    public void testCreate() {
        Entity entity = new Entity();
        entity.setId("5");
        entity.setCreateDate(new DateTime(2015,05,27,0,0).toDate());
        entity.setUpdateDate(new DateTime(2015,05,27,0,0).toDate());
        entity.setSystem("systemC");
        entity.setScore(5.7);
        IndexQuery query = new IndexQueryBuilder().withObject(entity).withId(entity.getId()).build();
        template.index(query);
    }

I can get the mapping of the created entity:

{
   "entity-index": {
      "mappings": {
         "entity-type": {
            "properties": {
               "@timestamp": {
                  "type": "long"
               },
               "createDate": {
                  "type": "date",
                  "store": true,
                  "format": "yyyy-MM-dd'T'hh:mm:ss.SSS'Z'"
               },
               "id": {
                  "type": "string"
               },
               "score": {
                  "type": "double"
               },
               "system": {
                  "type": "string"
               },
               "updateDate": {
                  "type": "date",
                  "format": "date_optional_time"
               }
            }
         }
      }
   }
}

However, when I search it curl -X GET /entity-index/_search, I get the following document:

 {
               "id": "5",
               "createDate": 1432656000000,
               "system": "systemC",
               "score": 5.7,
               "@timestamp": 1432656000000
 }

and the Date Fields are all Long type, how can I get the date format : '2015-08-17T12:00:00.000'?

4
Please try with a correct date format yyyy-MM-dd'T'HH:mm:ss.SSSZZ, i.e. the hours must be uppercased and no ticks around the Z timezone and Z must be doubled. You can also simply use the date_time format. Note that you need to wipe out your index first in order to test this change.Val
Thanks for your answer, I tried your suggestion, delete the index, change the pattern, but still show long as timestampfudy
Actually, your mapping is created correctly. The problem is more likely to come from the Jackson JSON serializer. You should try adding this annotation to your date fields: @JsonFormat (shape = JsonFormat.Shape.STRING, pattern ="yyyy-MM-dd'T'HH:mm:ss.SSSZZ"). See also some alternative solutions that might better suit your case.Val
yes, you are right, after change the code to : @JsonFormat (shape = JsonFormat.Shape.STRING, pattern ="yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") @JsonProperty(value = "@timestamp") private Date updateDate; problem is solvedfudy

4 Answers

19
votes

Your mapping is created correctly. The problem is more likely to come from the Jackson JSON serializer. You should try adding this annotation to your date fields: @JsonFormat (shape = JsonFormat.Shape.STRING, pattern ="yyyy-MM-dd'T'HH:mm:ss.SSSZZ").

There are also some alternative solutions that might better suit your case (i.e. creating a CustomDateSerializer, etc).

2
votes

Starting from Elasticsearch 7 you should't use yyyy but uuuu. e.g:

@Field(type = FieldType.Date, format = DateFormat.custom, pattern = "uuuu-MM-dd'T'HH:mm:ss.SSSZZ")
private Date lastModifiedDate;

You don't need @JsonProperty because now Spring Data Elasticsearch doesn't use Jackson but instead a MappingElasticsearchConverter. With this annotation, a converter is automatically created for this property and used.

1
votes

It worked for me with below settings. Note: delete your index before to test this change. Make sure that the patterns are same at all places.

@Field(type = FieldType.Date, store = true, format = DateFormat.custom, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
@JsonFormat (shape = JsonFormat.Shape.STRING, pattern ="yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
private Date date;
0
votes

Something to keep in mind:

JSON doesn’t have a date data type, so dates in Elasticsearch can either be:

  • Strings containing formatted dates, e.g. "2015-01-01" or "2015/01/01. 12:10:30".
  • A long number representing milliseconds-since-the-epoch.
  • An integer representing seconds-since-the-epoch.

Also from the same doc:

Dates will always be rendered as strings, even if they were initially supplied as a long in the JSON document

This implies that querying the data type for a date field will always be a string, a long or an integer. There is no special "Date" field in elastic search.

Read more here: https://www.elastic.co/guide/en/elasticsearch/reference/current/date.html