我们通过MySQL->Canal->ElasticSearch 进行数据同步的。版本分别是MySQL 8.0,Canal 1.1.7和 ElasticSearch 8.13.0 但是配置好了数据同步之后,通过 spring-data-elasticsearch 查询的时候,会出现时间类型无法转换的问题。
但是这样的方式有个问题,就是其中的时间类型,如 saleTime,会出现字段映射失败的情况,报错内容如下:
java.lang.RuntimeException: org.springframework.data.elasticsearch.core.convert.ConversionException:
Unable to convert value '2024-05-13T16:04:16+08:00' to java.util.Date for property 'saleTime'org.springframework.data.elasticsearch.core.convert.ConversionException:
Unable to convert value '2024-05-13T16:04:16+08:00' to java.util.Date for property 'saleTime'
at org.springframework.data.elasticsearch.core.convert.DatePropertyValueConverter.read(DatePropertyValueConverter.java:56)
at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter$Reader.convertOnRead(MappingElasticsearchConverter.java:524)
at org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter$Reader.propertyConverterRead(MappingElasticsearchConverter.java:518)
也就是说,日期类型,在 ES 中存储的是'2024-05-13T16:04:16+08:00'这种格式,而在代码中是无法转成我们想要的 Date 类型的。
这里我尝试了很多方法,比如通过设置saleTime的pattern,如:
@Field(name = "sale_time",type = FieldType.Date, format = {},pattern = "yyyy-MM-dd'T'HH:mm:ss'+08:00' ||yyyy-MM-dd||strict_date_optional_time||epoch_millis")private Date saleTime;
也是不行的。从 ES到代码这部分搞不定了,那接下来就想办法让 ES 存储的内容做一下改变吧。如果能让 ES 存储'2024-05-13 16:04:16' 而不是 '2024-05-13T16:04:16+08:00' 就能解决问题了。 这里尝试修改 ES 的索引配置,如:
PUT nfturbo_collection
{
"mappings": {
"properties": {
"sale_time": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss || yyyy-MM-dd'T'HH:mm:ss'+08:00 || strict_date_optional_time || epoch_millis"
},
}
}
}
也不行。
那就只剩最后一条路了,那就是在 Canal 上下功夫了,看看 ES 为啥会存 '2024-05-13T16:04:16+08:00' 这样的形式呢,
通过查看 Canal 的源码,可以看到在ESSyncUtil中,针对日期类型,他会使用如下方式进行格式化:
DateTime dateTime = new DateTime(((java.sql.Timestamp) val).getTime());
if (dateTime.getMillisOfSecond() != 0) {
res = dateTime.toString("yyyy-MM-dd'T'HH:mm:ss.SSS" + Util.timeZone);
} else {
res = dateTime.toString("yyyy-MM-dd'T'HH:mm:ss" + Util.timeZone);
}
这也是为啥会出现 '2024-05-13T16:04:16+08:00'这种格式的原因了,因为我们的项目不涉及到多时区,所以直接尝试着修改 Canal 源码。
找到ESSyncUtil中的8处日期转换部分内容,做如下修改:
修改后重新打包,编译成 jar包。因为我们的ES 是8.0的版本,所以最终到
workspace/canal-master/client-adapter/es8x/target下找到client-adapter.es8x-1.1.8-SNAPSHOT-jar-with-dependencies.jar这个编译后的包。
然后把他上传到 Canal 中,上传到Canal 安装目录的 plugin 目录下/root/package/canal-adapter/plugin