Elasticsearch MapperParsingException
使用 Java API 添加第一条索引记录时,如果 Elasticsearch 中还没有该索引则会自动创建该索引。
今天遇到一个奇怪的情况,有一条数据,通过该数据创建索引时有异常,通过别的数据则没有该错误。
最奇怪的是一旦通过正常的数据创建成功后,之前错误的数据也能正常插入了。
txt
MapperParsingException[failed to parse]; nested: IllegalArgumentException[mapper [priceDetails.amountSettlement] of different type, current_type [double], merged_type [long]];
数据库中该字段为 decimal(18, 2)
,Model 中为 BigDecimal
。
具体的数据 (Json 格式) 为:
json
{
"priceDetails": [
{
"amountSettlement": -0.1,
"amountSupplier": 0,
"amountType": 2,
"guid": "E382F203-71FE-4365-8332-0D430FE961DA",
"payType": 4,
"wholeGroupDemandGuid": "DE937A24-3E65-4B8B-A273-0833FB2CC5EC"
},
{
"amountSettlement": 100,
"amountSupplier": 100,
"amountType": 1,
"guid": "12E36173-9346-406F-BC98-24D92391CDFE",
"payType": 1,
"wholeGroupDemandGuid": "DE937A24-3E65-4B8B-A273-0833FB2CC5EC"
},
{
"amountSettlement": 0,
"amountSupplier": -1,
"amountType": 3,
"guid": "F1955B5E-99CD-4939-8396-6E740A05A52E",
"payType": 5,
"wholeGroupDemandGuid": "DE937A24-3E65-4B8B-A273-0833FB2CC5EC"
},
{
"amountSettlement": 0,
"amountSupplier": 0,
"amountType": 2,
"guid": "A32048B5-D78D-483E-8A29-C55EACD078DA",
"payType": 6,
"wholeGroupDemandGuid": "DE937A24-3E65-4B8B-A273-0833FB2CC5EC"
}
]
}
通过尝试发现在该值为带小数点的值时,创建索引会出异常。
猜测原因应该是还未创建索引类型时需要确定该属性的类型;
第一行带小数点被认为是 double
型;
第二行不带小数点被认为是 long
型;
导致两行的字段类型不一致,于是报错。
Elasticsearch 的坑爹事——记录一次 mapping field 修改过程
ElasticSearch
的索引一旦创建后不允许修改 field
的类型。
只能创建一个新索引,然后同步旧的索引数据到新索引。
自定义 Json
格式
暂时的解决方案: 使用 JsonBeanProcessor
将 BigDecimal
转成 String
型格式,在搜索引擎中字段为 String
型。
注意
这种方案会导致数值大小之类的比较变成字符串大小的比较。
代码:
java
package com.octopus.core;
import net.sf.json.JsonConfig;
import net.sf.json.processors.JsonValueProcessor;
import java.math.BigDecimal;
import java.text.DecimalFormat;
/**
* Created by liujiajia on 2016/11/8.
*/
public class JsonBigDecimalValueProcessor implements JsonValueProcessor {
private String format = "0.00";
public JsonBigDecimalValueProcessor() {
super();
}
public JsonBigDecimalValueProcessor(String format) {
super();
this.format = format;
}
@Override
public Object processArrayValue(Object o, JsonConfig jsonConfig) {
return process(o);
}
@Override
public Object processObjectValue(String s, Object o, JsonConfig jsonConfig) {
return process(o);
}
private Object process(Object value) {
if (value instanceof BigDecimal) {
// return ((BigDecimal) value).doubleValue();
DecimalFormat df = new DecimalFormat(format);
return df.format(value);
}
return value == null ? "0" : value.toString();
}
}
调用:
java
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.registerJsonValueProcessor(BigDecimal.class, new JsonBigDecimalValueProcessor());
return JSONObject.fromObject(object, jsonConfig).toString();