【问题标题】:How to make Spring Data Elasticsearch work with java.time.LocalDateTime for date如何使 Spring Data Elasticsearch 与 java.time.LocalDateTime 一起工作以获取日期
【发布时间】:2017-07-01 08:55:46
【问题描述】:

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

@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 化时,这里的模式似乎被忽略了。任何可能的提示?或者您可能知道如何在 Spring Data 中使用“内置”_timestamp 字段?

【问题讨论】:

    标签: java spring elasticsearch spring-data


    【解决方案1】:

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

    @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);
        }
      }
    }
    

    【讨论】:

    • 这看起来很有希望。默认情况下不使用 JavaTimeModule 的任何原因
    • 可能支持 JDK objectMapper.findAndRegisterModules(); 注册类路径中找到的所有模块...
    【解决方案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 提供了自定义转换功能,例如here

    基本上我们可以写一个从String到LocalDateTime的转换器,然后把日期模式放在那里。

    【讨论】:

    猜你喜欢
    • 2017-01-13
    • 2014-07-29
    • 1970-01-01
    • 2019-04-28
    • 1970-01-01
    • 2019-11-09
    • 2021-09-30
    • 1970-01-01
    • 2016-05-10
    相关资源
    最近更新 更多