如何使用Spring Data Elasticsearch正确格式化日期 [英] How to format date correctly using Spring Data Elasticsearch

查看:531
本文介绍了如何使用Spring Data Elasticsearch正确格式化日期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将SpringBoot 2.2.5与Elasticsearch 6.8.6一起使用.我正在从Spring Data Jest迁移到通过 ElasticsearchEntityMapper 使用Spring Data Elasticsearch REST传输机制.

I'm using SpringBoot 2.2.5 with Elasticsearch 6.8.6. I'm in progress of migrating from Spring Data Jest to using the Spring Data Elasticsearch REST transport mechanism with ElasticsearchEntityMapper.

我有一个 Date 字段,其定义如下:

I have a Date field with the following definition:

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

我想要这样存储在Elasticsearch中的日期:

I would like the date stored in Elasticsearch like this:

"date": "2020-04-02T14:49:05.672+0000"

启动应用程序时,将创建索引,但是当我尝试保存实体时,出现以下异常:

When I start the application, the index is created but when I try to save the entity I get the following exception:

Caused by: org.elasticsearch.client.ResponseException: method [POST], host [http://localhost:9200], URI [/trends/estrend?timeout=1m], status line [HTTP/1.1 400 Bad Request]
{"error":{"root_cause":[{"type":"mapper_parsing_exception","reason":"failed to parse field [date] of type [date] in document with id 'rS5UP3EB9eKtCTMXW_Ky'"}],"type":"mapper_parsing_exception","reason":"failed to parse field [date] of type [date] in document with id 'rS5UP3EB9eKtCTMXW_Ky'","caused_by":{"type":"illegal_argument_exception","reason":"Invalid format: \"1585905425266\" is malformed at \"5266\""}},"status":400}

关于我做错了什么以及应该如何解决的任何指示?

Any pointers on what I'm doing wrong and what I should do to fix it?

以下配置和实体定义:

@Configuration
public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {

    @Value("${spring.data.elasticsearch.host}")
    private String elasticSearchHost;

    @Value("${spring.data.elasticsearch.port}")
    private String elasticSearchPort;

    @Bean
    public RestHighLevelClient elasticsearchClient() {
        final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
        .connectedTo(elasticSearchHost + ":" + elasticSearchPort)
        .usingSsl()
        .build();
        return RestClients.create(clientConfiguration).rest();
    }

    @Bean
    public EntityMapper entityMapper() {
        ElasticsearchEntityMapper entityMapper = new ElasticsearchEntityMapper(elasticsearchMappingContext(), new DefaultConversionService());
        entityMapper.setConversions(elasticsearchCustomConversions());
        return entityMapper;
    }
}


package com.es.test;

import java.util.Date;
import java.util.UUID;
import com.fasterxml.jackson.annotation.JsonFormat;
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.FieldType;

@Document(indexName = "trends")
public class EsTrend {

    @Id
    private UUID id;

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

    private String entityOrRelationshipId;

    // getter and setters

}

更新 :

Update:

如果我禁用了 ElasticsearchEntityMapper bean,我不会得到异常,并且日期会以正确的格式写入Elasticsearch.我还需要为 ElasticsearchEntityMapper 配置什么吗?

If I disable the ElasticsearchEntityMapper bean, I don't get the exception and the date is written in the correct format to Elasticsearch. Is there anything else I need to configure for the ElasticsearchEntityMapper?

推荐答案

首先,请不要使用基于Jackson的默认映射器.在Spring Data Elasticsearch的下一个主要版本(4.0)中将其删除.然后将没有可用的选择,并且在内部使用 ElasticsearchEntityMapper .

First, please don't use the Jackson based default mapper. It is removed in the next major version of Spring Data Elasticsearch (4.0). Then there will be no choice available, and internally the ElasticsearchEntityMapperis used.

关于您的问题:Spring Boot当前使用的3.2版中的 ElasticsearchEntityMapper 不会使用 @Field 属性中与日期相关的信息进行转换实体,它仅用于索引映射的创建.这是一个缺少的功能或错误,已在下一个主要版本中修复,整个映射过程在那里进行了全面修订.

As to your problem: The ElasticsearchEntityMapperin version 3.2, which is used by Spring Boot currently, does not use the date relevant information from the @Field attribute to convert the entity, it is only used for the index mappings creation. This was a missing feature or bug and is fixed in the next major version, the whole mapping process was overhauled there.

在当前情况下可以做什么:您需要添加自定义转换器.您可以在配置类中执行以下操作:

What you can do in your current situation: You need to add custom converters. You can do this in your configuration class like this:

@Configuration
public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {

    private static SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");

    @Value("${spring.data.elasticsearch.host}")
    private String elasticSearchHost;

    @Value("${spring.data.elasticsearch.port}")
    private String elasticSearchPort;

    @Bean
    public RestHighLevelClient elasticsearchClient() {
        final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
            .connectedTo(elasticSearchHost + ":" + elasticSearchPort)
            .usingSsl()
            .build();
        return RestClients.create(clientConfiguration).rest();
    }

    @Bean
    public EntityMapper entityMapper() {
        ElasticsearchEntityMapper entityMapper = new ElasticsearchEntityMapper(elasticsearchMappingContext(), new DefaultConversionService());
        entityMapper.setConversions(elasticsearchCustomConversions());
        return entityMapper;
    }

    @Override
    public ElasticsearchCustomConversions elasticsearchCustomConversions() {
        return new ElasticsearchCustomConversions(Arrays.asList(DateToStringConverter.INSTANCE, StringToDateConverter.INSTANCE));
    }

    @WritingConverter
    enum DateToStringConverter implements Converter<Date, String> {
        INSTANCE;
        @Override
        public String convert(Date date) {
            return formatter.format(date);
        }
    }

    @ReadingConverter
    enum StringToDateConverter implements Converter<String, Date> {
        INSTANCE;
        @Override
        public Date convert(String s) {
            try {
                return formatter.parse(s);
            } catch (ParseException e) {
                return null;
            }
        }
    }
}

尽管如此,您仍然需要在 @Field 注释中使用dateformat,因为创建正确的索引映射是必需的.

You still need to have the dateformat in the @Field anotation though, because it is needed to create the correct index mappings.

并且您应该更改代码以使用Java 8引入的时间类,例如 LocalDate LocalDateTime ,Spring Data Elasticsearch支持开箱即用的时间类,而java.util.Date 将需要自定义转换器.

And you should change your code to use the Java 8 introduced time classes like LocalDate or LocalDateTime, Spring Data Elasticsearch supports these out of the box, whereas java.util.Date would need custom converters.

编辑09.04.2020 :添加了必要的 @WritingConverter @ReadingConverter 批注.

Edit 09.04.2020: added the necessary @WritingConverter and @ReadingConverter annotations.

编辑19.04.2020::Spring Data Elasticsearch 4.0将通过 @Field 开箱即用地支持 java.util.Date 类.注释.

Edit 19.04.2020: Spring Data Elasticsearch 4.0 will support the java.util.Date class out of the box with the @Field annotation as well.

这篇关于如何使用Spring Data Elasticsearch正确格式化日期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆