首页 > 解决方案 > 在 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

然后我尝试了此处建议的解决方法,但发现我必须在 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。我认为我可以调整您的解决方案,并使用 and 找到第二次和第三次出现 _ 的string.indexOf("_", 1)索引string.indexOf("_", 2)。但是,我总是得到与 相同的结果string.indexOf("_"),没有任何额外的参数(即结果总是 _ 的第一次出现的索引)。

标签: elasticsearchsplitelasticsearch-painless

解决方案


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

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

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

推荐阅读