Skip to content

Elasticsearch MapperParsingException

🏷️ Elasticsearch

使用 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 的类型。

只能创建一个新索引,然后同步旧的索引数据到新索引。


net.sf.json.JsonConfig 使用详解

自定义 Json 格式


暂时的解决方案: 使用 JsonBeanProcessorBigDecimal 转成 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();