You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Data Elasticsearch中如何为TemporalAccessor类型HashMap指定Field类型

Spring Data Elasticsearch 配置Map<String, ZonedDateTime>字段类型的方案

直接在Map<String, ZonedDateTime>类型的字段上加@Field(FieldType.Date)注解时,Spring Data Elasticsearch会将整个Map容器识别为日期类型尝试解析,无法正确识别Map value的日期类型;如果不加类型配置则会抛出如下错误:

Type .. of property .. is a TemporalAccessor class but has neither a @Field annotation defining the date type nor a registered converter for writing! It will be mapped to a complex object in Elasticsearch!

中文翻译:属性xxx的类型属于TemporalAccessor类,但既没有定义日期类型的@Field注解,也没有注册可用于写入的转换器!它将被映射为Elasticsearch中的复杂对象!

解决方案1:自定义类型转换器(推荐,无额外结构层级)

通过自定义转换器实现Map类型的序列化和反序列化,步骤如下:

  1. 实现写入转换器,将Map<String, ZonedDateTime>序列化为ES可识别的Map<String, String>,值为标准日期格式字符串:
import org.springframework.core.convert.converter.Converter;
import java.time.ZonedDateTime;
import java.util.Map;
import java.util.stream.Collectors;

public class ZonedDateTimeMapWriteConverter implements Converter<Map<String, ZonedDateTime>, Map<String, String>> {
    @Override
    public Map<String, String> convert(Map<String, ZonedDateTime> source) {
        return source.entrySet().stream()
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        // 可通过DateTimeFormatter自定义需要的日期格式
                        entry -> entry.getValue().toString()
                ));
    }
}
  1. 实现读取转换器,将ES返回的Map<String, String>反序列化为Map<String, ZonedDateTime>:
import org.springframework.core.convert.converter.Converter;
import java.time.ZonedDateTime;
import java.util.Map;
import java.util.stream.Collectors;

public class ZonedDateTimeMapReadConverter implements Converter<Map<String, String>, Map<String, ZonedDateTime>> {
    @Override
    public Map<String, ZonedDateTime> convert(Map<String, String> source) {
        return source.entrySet().stream()
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        // 和写入时的格式对应解析
                        entry -> ZonedDateTime.parse(entry.getValue())
                ));
    }
}
  1. 注册转换器到Spring Data Elasticsearch配置中:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.config.ElasticsearchConfigurationSupport;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions;
import java.util.List;

@Configuration
public class ElasticsearchConfig extends ElasticsearchConfigurationSupport {
    @Bean
    @Override
    public ElasticsearchCustomConversions elasticsearchCustomConversions() {
        return new ElasticsearchCustomConversions(List.of(
                new ZonedDateTimeMapWriteConverter(),
                new ZonedDateTimeMapReadConverter()
        ));
    }
}
  1. 字段上标注类型为Object即可:
@Field(type = FieldType.Object)
private Map<String, ZonedDateTime> timePoints = new HashMap<>();

解决方案2:封装自定义嵌套类

如果不想写转换器,可以将ZonedDateTime封装为内部类,给内部类的日期字段加日期类型注解:

// 自定义封装类
static class TimePoint {
    @Field(type = FieldType.Date, format = DateFormat.ISO_DATE_TIME)
    private ZonedDateTime time;
    // getter、setter省略
}

// 字段修改为
private Map<String, TimePoint> timePoints = new HashMap<>();

该方案的缺点是ES中存储的结构会多一层time字段,查询和返回数据时需要额外处理层级。

内容的提问来源于stack exchange,提问作者Alex1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 23:36:02