ES浮点数被识别为字符串
最近准备把ES的版本从5.1.2升到6.2.4,将Kafka的数据写入ES的工具类ESPersistor需要进行相应api的调整。在5.1.2的java api中,使用IndexRequest.source(String source)
来设置要写入的json字符串,但在6.2.4中这个函数已经被移除,可选的替代者有以下几种(source的重载函数还有很多,但这里不在讨论范围内)
1
|
IndexRequest.source(String source, XContentType xContentType)
|
第一种写法没有问题,指定XContentType.JSON就和之前版本的写入效果完全一样
第二种写法就发生了比较诡异的现象,假如json字符串中有值为浮点数,比如{“value”: 0.1},写入ES之后类型并不是float,而是text。假如字段value之前并不存在,那么ES会自动创建类型为text的字段value,后续就没办法对value做数值类型的计算了。那么为什么浮点类型会被认为是字符串呢?看代码
1
|
public IndexRequest source(Map source, XContentType contentType) throws ElasticsearchGenerationException {
|
参数Map source实际上是会被转换成XContentBuilder来处理,再看builder.map(source);
1
|
private XContentBuilder map(Map<String, ?> values, boolean ensureNoSelfReferences) throws IOException {
|
先检查json(map)中是否有自我引用,然后遍历所有Entry,将key/value写到XContentBuilder中,再看看值是怎么写入的unknownValue(value.getValue(), false);
1
|
private void unknownValue(Object value, boolean ensureNoSelfReferences) throws IOException {
|
判断value的类型,如果是ES标准数据类型,直接从WRITERS中获取相应的Writer写入,例如对于Float,调用(builder, value) -> builder.value((Float) value)
写入;对于其他类型,调用相应的value重载函数写入;如果列举的类型都不匹配,则当做字符串来处理
DEBUG一下,发现JSONObject {“value”: 0.1} 执行到这的时候,value.getClass()居然是BigDecimal,跟所有列举的类型都不匹配,所有就当字符串处理了,写入ES时就成了{“value”: “0.1”},那么为什么值的类型会变成BigDecimal呢?测试一下
1
|
JSONObject data = new JSONObject();
|
打印结果是class java.lang.Double
,没有问题,这是new一个JSONObject的情况,再测试一下字符串parse成JSONObject的情况
1
|
JSONObject data = JSON.parseObject("{\"value\":0.1}");
|
打印结果是class java.math.BigDecimal
,OK破案了,真凶是fastjson,它在parseObject时会把Float识别为BigDecimal,看一下源码,parseObject会调用parse(String text, int features)
函数,features的值是常量JSON.DEFAULT_PARSER_FEATURE,这个常量是由一系列的Feature位或计算出来的
1
|
public static int DEFAULT_PARSER_FEATURE;
|
其中有个Feature是UseBigDecimal,这个Feature会使得DefaultJSONParser中会把Float转成BigDecimal
1
|
case LITERAL_FLOAT:
|
问题根源找到了,解决也就不难了,自定义一个features,把Feature.UseBigDecimal从DEFAULT_PARSER_FEATURE中用异或去掉,然后JSON.parse使用自定义的features就可以了
1
|
int features = JSON.DEFAULT_PARSER_FEATURE ^ Feature.UseBigDecimal.getMask();
|
打印class java.lang.Double
,解决
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?