使用 Elasticsearch Painless 更改字段值

Change field values using Elasticsearch Painless

我想查看对象alert下每个字段的长度。

如果比X长,改成value was truncated since it was too long

"_source" : {
          "random" : 123455,
          },
          "@timestamp" : "2021-10-15T21:55:12.938+0000",
          "application" : "app",
          "alert" : {
            "app_key" : "XYZ",
            "host" : "Hostname",
            "check" : "CPU overloaded",
            "status" : "ok"
          },

出于某种原因,我在尝试应用我的脚本时遇到此错误:

    "type" : "script_exception",
    "reason" : "runtime error",
    "script_stack" : [
      "java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1584)",
      "java.base/java.util.HashMap$EntryIterator.next(HashMap.java:1617)",
      "java.base/java.util.HashMap$EntryIterator.next(HashMap.java:1615)",
      "for (alert in ctx._source.alert.entrySet())\n      {\n      ",
      "                               ^---- HERE"
    ],
    "script" : " ...",
    "lang" : "painless",
    "position" : {
      "offset" : 38,
      "start" : 7,
      "end" : 65
    },
    "caused_by" : {
      "type" : "concurrent_modification_exception",
      "reason" : null

脚本:

{
  "script": {
    "lang": "painless",
    "source": """
      for (alert in ctx._source.alert.entrySet())
      {
      if (alert.getValue().length() > params.number_of_characters) {
        ctx._source.alert[alert] = "value was truncated since it was too long"
      }
      }
    """,
    "params": {
      "number_of_characters": 5
    }
  }
}

迭代entrySet返回的集合时不能直接修改map,只能通过entry的setValue方法修改。

根据 doc entrySet():

Returns a Set view of the mappings contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa. If the map is modified while an iteration over the set is in progress (except through the iterator's own remove operation, or through the setValue operation on a map entry returned by the iterator) the results of the iteration are undefined. The set supports element removal, which removes the corresponding mapping from the map, via the Iterator.remove, Set.remove, removeAll, retainAll and clear operations. It does not support the add or addAll operations.

尝试使用以下脚本:

for (alert in ctx._source.alert.entrySet()){
    if (alert.getValue().length() > params.number_of_characters) {
        alert.setValue("value was truncated")      
    }      
}

最终,在 Nicolas 的帮助下,我使用了这个:

PUT _ingest/pipeline/rawpayload-ingest/
{
  "processors": [
    {
      "script": {
        "description": "Loop through all fields in alert object and shorten them if needed",
        "lang": "painless",
        "source": """
          for (field in ctx.alert.entrySet()) {
            if (field.getValue() instanceof String) {
              if (field.getValue().length() > params.number_of_characters) {
              field.setValue(field.getValue().substring(0, params.number_of_characters) + "...truncated")
              }   
            }
          }
        """,
        "params": {
          "number_of_characters": 512
        }
      }
    }
  ]
}