在 Painless/ELK 中分割字符串

问题描述 投票:0回答:3

我有一个字符串字段“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("_")
相同的结果,没有任何额外的参数(即结果始终是 _ 第一次出现的索引)。

elasticsearch split elasticsearch-painless
3个回答
5
投票

启用正则表达式并不是非常复杂,但它需要重新启动集群,并且根据环境的不同,这对您来说可能并不容易。

实现这一目标的另一种方法是采用“旧方法”。首先,为每个脚本字段创建一个可重用脚本。该脚本所做的只是找到第一次、第二次、第三次和最后一次出现的

_
符号并返回分割元素。它将要分割的字段名称和要返回的子字符串的索引作为输入:

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"
      ]
    }
  }

4
投票

您可以使用

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

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

因此,reason 将保留剩余的字符串:

Your warning


0
投票

完成“George Ts.”伟大的答案...

这对我来说很方便,带有定界符“-”的语法,甚至在 Opensearch-dashboards

String[] message = message.splitOnToken("-");

// Return the first part if it exists
if (message.length > 1) {
    return message[0];  // Adjust index as needed
} else {
    return 'empty';
}
© www.soinside.com 2019 - 2024. All rights reserved.