如何使Spring Data Elasticsearch与java.time.LocalDateTime一起工作

2022-09-04 02:22:47

我正在使用Spring Data支持Elasticsearch。下面是时间戳字段映射:

@Field(type = FieldType.Date, index = FieldIndex.not_analyzed, store = true,
        format = DateFormat.custom, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZZ")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern ="yyyy-MM-dd'T'HH:mm:ss.SSSZZ")
private LocalDateTime timestamp;

这将导致 Elasticsearch 中字段的映射,如下所示:

"timestamp":{"type":"date","store":true,"format":"yyyy-MM-dd'T'HH:mm:ss.SSSZZ"}

当我使用java.util.Date代替时,一切都很好。但是,当我切换到java.time.LocalDateTime时,如上所述,发送到Elasticsearch的文档会导致异常。以下是文档(时间戳字段仅为简洁起见):

"timestamp": {
    "hour":7, "minute":56, "second":9, "nano":147000000, "year":2017, "month":"FEBRUARY",
    "dayOfMonth":13, "dayOfWeek":"MONDAY", "dayOfYear":44, "monthValue":2, "chronology": {
        "id":"ISO", "calendarType": "iso8601"
    }
}

例外:

MapperParsingException[failed to parse [timestamp]]; nested: IllegalArgumentException[unknown property [hour]];
(...)
Caused by: java.lang.IllegalArgumentException: unknown property [hour]

在 json 化文档时,看起来此处忽略了该模式。任何可能的提示?或者,您可能知道如何将“内置”_timestamp字段与Spring Data一起使用?


答案 1

选中 https://github.com/spring-projects/spring-data-elasticsearch/wiki/Custom-ObjectMapper 以添加到您的 .JavaTimeModuleObjectMapper

@Configuration
public class ElasticSearchConfiguration {

  @Bean
  public ElasticsearchTemplate elasticsearchTemplate(Client client) {
    return new ElasticsearchTemplate(client, new CustomEntityMapper());
  }

  public static class CustomEntityMapper implements EntityMapper {

    private final ObjectMapper objectMapper;

    public CustomEntityMapper() {
      objectMapper = new ObjectMapper();
      objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
      objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
      objectMapper.registerModule(new CustomGeoModule());
      objectMapper.registerModule(new JavaTimeModule());
    }

    @Override
    public String mapToString(Object object) throws IOException {
      return objectMapper.writeValueAsString(object);
    }

    @Override
    public <T> T mapToObject(String source, Class<T> clazz) throws IOException {
      return objectMapper.readValue(source, clazz);
    }
  }
}

答案 2

我遇到了类似的问题:日期值中的“Z”被视为字符,因此日期解析失败。我的解决方案是使用自定义模式来确保转换正确:

@Field(type = FieldType.Date, format = DateFormat.custom, pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'")
private LocalDateTime dateField;

如果我们不想一次又一次地在不同的字段上重复该模式,我们可以尝试集中到转换逻辑中。Spring Data Elastic Search提供自定义转换功能,请查看此处的示例。

基本上,我们可以编写一个从 String 到 LocalDateTime 的转换器,并将日期模式放在那边。


推荐