在 Painless/ELK 中分割一个字符串

Split a string in Painless/ELK

我有一个字符串字段“myfield.keyword”,其中的条目具有以下格式:

AAA_BBBB_CC

DDD_EEE_F

我正在尝试创建一个输出第一个 _ 之前的子字符串的脚本字段,一个输出第一个和第二个 _ 之间的子字符串的脚本字段,以及一个输出第二个 _ 之后的子字符串的脚本字段。

我试图用.split('_')来做这个,但是发现这个方法在Painless中不可用:

def newfield = "";
def path = doc[''myfield.keyword].value;
if (...)
{newfield = path.split('_')[1];} else {newfield="null";}
return newfield

然后我尝试了建议的解决方法 here,但发现我必须在 Elastic 中启用正则表达式(这在我的情况下是不可能的):

def newfield = "";
def path = doc[''myfield.keyword].value;
if (...)
{newfield = /_/.split(path)[1];} else {newfield="null";}
return newfield

有没有预先假定启用正则表达式的方法来做到这一点?

编辑:

感谢您提供如此优雅的解决方案,Val。这回答了我问的问题。但是,我的问题结构不正确。特别是,需要拆分的字符串出现了四次“_”。类似于:

AAA_BB_CCC_DD_E

FFF_GGG_HH_JJJJ_KK

所以,如果我没理解错的话,indexOf()lastIndexOf()不能给我BB、CCC或DD。我认为我可以调整您的解决方案,并使用 string.indexOf("_", 1)string.indexOf("_", 2) 找到 _ 第二次和第三次出现的索引。但是,我总是得到与 string.indexOf("_") 相同的结果,没有任何额外的参数(即结果始终是 _ 第一次出现的索引)。

启用正则表达式并不十分复杂,但它需要重新启动集群,这对您来说可能并不容易,具体取决于环境。

实现此目的的另一种方法是使用“旧方法”。首先,您为每个脚本字段创建一个可重用的脚本。该脚本所做的只是找到 _ 符号和 return 的第一次、第二次、第三次和最后一次出现的拆分元素。它将要拆分的字段名称和子字符串的索引作为输入 return:

POST _scripts/my-split
{
  "script": {
    "lang": "painless",
    "source": """
      def str = doc[params.field].value;
      def first = str.indexOf("_");
      def second = first + 1 + str.substring(first + 1).indexOf("_");
      def third = second + 1 + str.substring(second + 1).indexOf("_");
      def last = str.lastIndexOf("_");
      def parts = [
           str.substring(0, first), 
           str.substring(first + 1, second), 
           str.substring(second + 1, third), 
           str.substring(third + 1, last), 
           str.substring(last + 1)
      ];
      return parts[params.index];
    """
  }
}

然后你可以简单地为每个部分定义一个脚本字段,如下所示:

POST test/_search
{
  "script_fields": {
    "first": {
      "script": {
        "id": "my-split",
        "params": {
          "field": "myfield.keyword",
          "index": 0
        }
      }
    },
    "second": {
      "script": {
        "id": "my-split",
        "params": {
          "field": "myfield.keyword",
          "index": 1
        }
      }
    },
    "third": {
      "script": {
        "id": "my-split",
        "params": {
          "field": "myfield.keyword",
          "index": 2
        }
      }
    }
  }
}

您得到的响应将如下所示:

  {
    "_index" : "test",
    "_type" : "_doc",
    "_id" : "ykS-l3UBeO1HTBdDvTZd",
    "_score" : 1.0,
    "fields" : {
      "first" : [
        "AAA"
      ],
      "second" : [
        "BBBB"
      ],
      "third" : [
        "CC"
      ]
    }
  }

您可以使用 str.splitOnToken("_") 并将每个结果检索为一个数组,并出于您的任何目的循环该数组。 您甚至可以拆分变量标记,例如:

def message = "[LOG] Something something WARNING: Your warning";
def reason = message.splitOnToken("WARNING: ")[1];

所以 reason 将保留剩余的字符串:Your warning.