某用户Logstash消费Kafka数据写入ES报错,"cannot be changed from type [long] to [text]"处理过程

2022-08-06 19:10:28 浏览数 (1)

一、前言

某用户通过logstash消费Kafka数据写入ES时报错,导致数据写入ES失败。需要排查原因

  1. 问题排查报错信息如下:

Could not index event to Elasticsearch. {:status=>400, :action=>["index", {:_id=>nil, :_index=>"XXXXXX-2022.08", :routing=>nil, :_type=>"_doc"}, #<LogStash::Event:0x153461e0>], :response=>{"index"=>{"_index"=>"XXXXXX-2022.08

", "_type"=>"_doc", "_id"=>"AKkgXoIBJ6THvkxd4efv", "status"=>400, "error"=>{"type"=>"illegal_argument_exception", "reason"=>"mapper [modules.subModules.items.value] cannot be changed from type [long] to [text]"}}}}

大意是"modules.subModules.items.value"这个字段的类型是长整型,但是写入ES的时候变成了字符串类型text.类型转换错误导致数据写入失败。

二、数据测试

测试一:

代码语言:javascript复制

PUT nginx-hezhenserver/_doc/1
{
  "modules": [
    {
      "name": "IPC",
      "subModules": [
        {
          "name": "cpuUse",
          "items": [
            {
              "name": "all",
              "value": "31.63"
            },
            {
              "name": "cpu1",
              "value": 29                    //注意这里的value的值的不同。
            }
          ]
        }
      ]
    }
  ]
}

报错如下:

插入文档报错插入文档报错

测试二:

代码语言:javascript复制
PUT nginx-hezhenserver/_doc/1
{
  "modules": [
    {
      "name": "IPC",
      "subModules": [
        {
          "name": "cpuUse",
          "items": [
            {
              "name": "all",
              "value": "31.63"
            },
            {
              "name": "cpu1",
              "value": "29"           加引号//注意这里的value的值的不同,将value值的格式改为一致。
            }
          ]
        }
      ]
    }
  ]
}

数据创建成功。

从以上对比中,我们可以看到,这种object类型的对象子字段内容中数据类型不一致时,在存入ES的时候,会报类型转换错误,默认都会转为字符串类型存储。

三、解决办法

由于用户这种类型的字段内容都是数字类型,那这里就统一定义为long. 可以在template里加一个动态模板,用来将这类的字段写入ES时自动转为long类型。由于这里是对象字段object 子字段,这里需要用到path.match,模板里设置如下:

代码语言:javascript复制
    {
        "message22": {
          "mapping": {
            "type": "long"
          },
         "path_match" : "modules.subModules.items.value"
        }
      }
    //将此类index下的value对象字段映射成long.

执行上述模板后,再生成一个new index.

还是上一个测试语句。

代码语言:javascript复制
PUT nginx-hezhenserver/_doc/1
{
  "modules": [
    {
      "name": "IPC",
      "subModules": [
        {
          "name": "cpuUse",
          "items": [
            {
              "name": "all",
              "value": "31.63"
            },
            {
              "name": "cpu1",
              "value": 29
            }
          ]
        }
      ]
    }
  ]
}

再次执行,发现执行成功。查看mapping,values子字段变成了long.其他对象字段变成了text。

那么问题到这里基本就解决了,但是由于用户logstash消费的源数据不统一,value数组里的内容不规范,导致写入ES的时候还是报错。

代码语言:javascript复制
PUT nginx-hezhenserver/_doc/1
{
  "modules": [
    {
      "name": "IPC",
      "subModules": [
        {
          "name": "cpuUse",
          "items": [
            {
              "name": "all",
              "value": "31.63"
            },
            {
              "name": "cpu1",
              "value": 29
            },{
              "name": "cpu1",
              "value": "689MZH"   //字符串类型的value
            }
          ]
        }
      ]
    }
  ]
}

报错如下:

写入报错2写入报错2

这个意思是这个写入的value里的内容ES识别到输入的是String.不能转成long. 解析失败。

由于用户侧无法控制写入数据的标准性,那只能ES侧再调整模板,直接改为text类型即可。调整如下:

代码语言:javascript复制
{
        "message22": {
          "mapping": {
            "type": "text"
          },
         "path_match" : "modules.subModules.items.value"
        }
      }

再次执行上述index.索引即创建成功。

那么以上调整,客户此类logstash消费kafka异常的数据写入问题就全部解决。

四、总结

这里主要用到了Elasticseach的动态模板,用到了对象字段path_match组合,特地记录了这个问题。

0 人点赞