最近壹哥的一个学生,在利用spring-data-elasticsearch访问ElasticSearch(ES)时,遇到了一个关于日期类型的BUG,困扰了很久。然后他就找壹哥给他解决,接下来壹哥就把解决的过程给大家复现一下,希望本文可以给遇到同样问题的同学一点启发。
我们先来看看他的POM.xml文件配置,如下所示:
- <parent>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-parentartifactId>
- <version>2.2.9.RELEASEversion>
- <relativePath/>
- parent>
-
- <dependencies>
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-data-elasticsearchartifactId>
- dependency>
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-webartifactId>
- dependency>
- dependencies>
实体类的代码如下:
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- @Document(indexName = "user_info",shards = 1,replicas = 1,createIndex = false)
- public class UserInfo {
-
- @Id
- @Field(type = FieldType.Long)
- private Long id;
-
- @Field(type = FieldType.Keyword)
- private String name;
-
- @Field(type = FieldType.Text,analyzer = "ik_max_word",searchAnalyzer = "ik_max_word")
- private String remark;
-
- @Field(type = FieldType.Date,format = DateFormat.date_time)
- private Date jobday;
-
- }
创建索引的单元测试类代码如下:
- @Test
- void createIndex() {
- // 创建索引
- elasticsearchRestTemplate.createIndex(UserInfo.class);
-
- // 声明索引中 mapping部分
- elasticsearchRestTemplate.putMapping(UserInfo.class);
- }
以下是ES中创建的索引 Mapping结构,其中日期类型的format为date_time。

看了以上代码,你能猜出来哪里有问题吗?其实这个bug是发生在写入操作中,代码如下:
- @Test
- void save() {
-
- final UserInfo userInfo = new UserInfo();
- userInfo.setId(100l);
- userInfo.setName("张三");
- userInfo.setJobday(new Date());
- userInfo.setRemark("张三是法外狂徒");
-
- userRepository.save(userInfo);
- }
我们来看看产生的异常信息。
- Caused by: ElasticsearchException[Elasticsearch exception [type=illegal_argument_exception, reason=Invalid format: "1669366585010" is malformed at "5010"]]
- at org.elasticsearch.ElasticsearchException.innerFromXContent(ElasticsearchException.java:509)
- at org.elasticsearch.ElasticsearchException.fromXContent(ElasticsearchException.java:420)
- at org.elasticsearch.ElasticsearchException.innerFromXContent(ElasticsearchException.java:450)
- at org.elasticsearch.ElasticsearchException.failureFromXContent(ElasticsearchException.java:616)
- at org.elasticsearch.rest.BytesRestResponse.errorFromXContent(BytesRestResponse.java:169)
- ... 87 more
通过查看报错信息,我们可以发现该bug是由于写入请求时,给定的日期格式与mapping中限定的date_time格式不一致导致的!
既然是时间格式有问题,那么我们就需要知道写请求中的日期格式,与ES mapping中的date_time格式分别是什么。
从日志中我们可以看到,写入请求中的日期格式为 1669366585010,即long型整数的时间戳格式。根据ES的官方文档,我们可以看到date_time的格式要求如下:

我们可以可以看到,ES里的格式默认为: yyyy-MM-dd'T'HH:mm:ss.SSSZ
这样bug产生的原因就很清晰了,该学生写入请求中的是 long,而ES索引中要求的是 yyyy-MM-dd'T'HH:mm:ss.SSSZ,这两个不一致,自然就报错了!
既然我们现在明白了bug的产生原因,解决起来也就很容易了,只要把日期格式匹配上即可。现在springboot-data中写入的是long,只要让ES mapping中能够接收long格式即可。
修改后的代码配置如下所示:
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- @Document(indexName = "user_info",shards = 1,replicas = 1,createIndex = false)
- public class UserInfo {
-
- @Id
- @Field(type = FieldType.Long)
- private Long id;
-
- @Field(type = FieldType.Keyword)
- private String name;
-
- @Field(type = FieldType.Text,analyzer = "ik_max_word",searchAnalyzer = "ik_max_word")
- private String remark;
-
- // 这里不要写 format即可,默认的date类型就可以接收 long值
- @Field(type = FieldType.Date)
- private Date jobday;
-
- }
mapping结构如下所示,这里的date就可以接收long类型的值了。

接下来我们重新进行单元测试,此时发现,代码可以正常执行通过了。
- @Test
- void save() {
-
- final UserInfo userInfo = new UserInfo();
- userInfo.setId(100l);
- userInfo.setName("张三");
- userInfo.setJobday(new Date());
- userInfo.setRemark("张三是法外狂徒");
-
- userRepository.save(userInfo);
- }

现在你知道这个问题怎么解决了吗?以后再遇到类似的问题,不要慌,沉下心来仔细想一下问题出在哪里,然后一点点针对该问题进行分析解决。如果你实在解决不了,给壹哥私信,我来帮你搞定。关注Java架构栈,干货天天都不断哦!