资讯详情

Elasticsearch报错:cannot write xcontent for unknown value of type class java.math.BigDecimal

1. 问题与分析

在使用Elasticsearch进行index当数据发现错误如下:

java.lang.IllegalArgumentException: cannot write xcontent for unknown value of type class java.math.BigDecimal  at org.elasticsearch.common.xcontent.XContentBuilder.unknownValue(XContentBuilder.java:755)  at org.elasticsearch.common.xcontent.XContentBuilder.value(XContentBuilder.java:726)  at org.elasticsearch.common.xcontent.XContentBuilder.field(XContentBuilder.java:711)  at org.elasticsearch.index.query.BaseTermQueryBuilder.doXContent(BaseTermQueryBuilder.java:154)  at org.elasticsearch.index.query.AbstractQueryBuilder.toXContent(AbstractQueryBuilder.java:82)  at org.elasticsearch.index.query.BoolQueryBuilder.doXArrayContent(BoolQueryBuilder.java:275)  at org.elasticsearch.index.query.BoolQueryBuilder.doXContent(BoolQueryBuilder.java:256)  at org.elasticsearch.index.query.AbstractQueryBuilder.toXContent(AbstractQueryBuilder.java:82)  at org.elasticsearch.common.xcontent.XContentBuilder.value(XContentBuilder.java:779)  at org.elasticsearch.common.xcontent.XContentBuilder.value(XContentBuilder.java:772)  at org.elasticsearch.common.xcontent.XContentBuilder.field(XContentBuilder.java:764)  at org.elasticsearch.search.builder.SearchSourceBuilder.toXContent(SearchSourceBuilder.java:1184)  at org.elasticsearch.common.xcontent.XContentHelper.toXContent(XContentHelper.java:349)  at org.elasticsearch.search.builder.SearchSourceBuilder.toString(SearchSourceBuilder.java:1558)  at org.elasticsearch.search.builder.SearchSourceBuilder.toString(SearchSourceBuilder.java:1553)  at java.lang.String.valueOf(String.java:2994)  at java.lang.StringBuilder.append(StringBuilder.java:131)  at org.elasticsearch.action.search.SearchRequest.toString(SearchRequest.java:516) 

显然,从异常信息来看ES无法接受BigDecimal经过百度,类型确实如此。在博文评论中解释如下:

在客户端代码中客户端代码中定义为java.math.BigDecimal,而ES不支持这种类型的原因。2.2没有问题,因为以前transport client在发送数据之前,将其序列化为json,而在5.x以后,内部使用transport protocol,如果数据类型不匹配,就会出错。

所以数据类型的定义上,需要使用ES支持类型。

2. 解决方案

2.1 方案一:转化为其他ES支持的数据类型

我使用的是6.4.2版本的Elasticsearch,不支持这个版本BigDecimal或者BigInteger数据类型,所以在index到Elasticsearch以前需要转换成其他类型的数据,这里要注意不要溢出数据:

  • BigDecimal要转变成Double类型
  • BigInteger要转变成Long类型

2.2 方案二:使用更高版本ES

我在看6.7.1版本的Elasticsearch发现源码已经支持了BigDecimal或者BigInteger数据类型,直接使用该版本或更高版本。

2.3 以下是两个版本支持的数据类型的源代码:

6.4.2版本的Elasticsearch相关源码:

Map<Class<?>, Writer> writers = new HashMap<>(); writers.put(Boolean.class, (b, v) -> b.value((Boolean) v)); writers.put(Byte.class, (b, v) -> b.value((Byte) v)); writers.put(byte[].class, (b, v) -> b.value((byte[]) v)); writers.put(Date.class, XContentBuilder::timeValue); writers.put(Double.class, (b, v) -> b.value((Double) v)); writers.put(double[].class, (b, v) -> b.values((double[]) v)); writers.put(Float.class, (b, v) -> b.value((Float) v)); writers.put(float[].class, (b, v) -> b.values((float[]) v)); writers.put(Integer.class, (b, v) -> b.value((Integer) v)); writers.put(int[].class, (b, v) -> b.values((int[]) v)); writers.put(Long.class, (b, v) -> b.value((Long) v)); writers.put(long[].class, (b, v) -> b.values((long[]) v)); writers.put(Short.class, (b, v) -> b.value((Short) v)); writers.put(short[].class, (b, v) -> b.values((short[]) v)); writers.put(String.class, (b, v) -> b.value((String) v)); writers.put(String[].class, (b, v) -> b.values((String[]) v)); writers.put(Locale.class, (b, v) -> b.value(v.toString())); writers.put(Class.class, (b, v) -> b.value(v.toString())); writers.put(ZonedDateTime.class, (b, v) -> b.value(v.toString())); writers.put(Calendar.class, XContentBuilder::timeValue); writers.put(GregorianCalendar.class, XContentBuilder::timeValue); 

6.7.1版本的Elasticsearch相关源码:

Map<Class<?>, Writer> writers = new HashMap<>(); writers.put(Boolean.class, (b, v) -> b.value((Boolean) v)); writers.put(Byte.class, (b, v) -> b.value((Byte) v)); writers.put(byte[].class, (b, v) -> b.value((byte[]) v)); writers.put(Date.class, XContentBuilder::timeValue); writers.put(Double.class, (b, v) -&g; b.value((Double) v));
writers.put(double[].class, (b, v) -> b.values((double[]) v));
writers.put(Float.class, (b, v) -> b.value((Float) v));
writers.put(float[].class, (b, v) -> b.values((float[]) v));
writers.put(Integer.class, (b, v) -> b.value((Integer) v));
writers.put(int[].class, (b, v) -> b.values((int[]) v));
writers.put(Long.class, (b, v) -> b.value((Long) v));
writers.put(long[].class, (b, v) -> b.values((long[]) v));
writers.put(Short.class, (b, v) -> b.value((Short) v));
writers.put(short[].class, (b, v) -> b.values((short[]) v));
writers.put(String.class, (b, v) -> b.value((String) v));
writers.put(String[].class, (b, v) -> b.values((String[]) v));
writers.put(Locale.class, (b, v) -> b.value(v.toString()));
writers.put(Class.class, (b, v) -> b.value(v.toString()));
writers.put(ZonedDateTime.class, (b, v) -> b.value(v.toString()));
writers.put(Calendar.class, XContentBuilder::timeValue);
writers.put(GregorianCalendar.class, XContentBuilder::timeValue);
writers.put(BigInteger.class, (b, v) -> b.value((BigInteger) v));
writers.put(BigDecimal.class, (b, v) -> b.value((BigDecimal) v));

可以发现,在6.7.1版本的源码里,多出了最后的两种数据类型的支持:BigIntegerBigDecimal

标签: xtkj智能传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

 锐单商城 - 一站式电子元器件采购平台  

 深圳锐单电子有限公司