如何使用Spring Data Elasticsearch正确格式化日期 [英] How to format date correctly using 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 ElasticsearchEntityMapper
is used.
关于您的问题:Spring Boot当前使用的3.2版中的 ElasticsearchEntityMapper
不会使用 @Field
属性中与日期相关的信息进行转换实体,它仅用于索引映射的创建.这是一个缺少的功能或错误,已在下一个主要版本中修复,整个映射过程在那里进行了全面修订.
As to your problem: The ElasticsearchEntityMapper
in 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屋!