Logstash 过滤器 - 将键名从 "this_is_example" => 1 转换为 [this][is][example] => 1

Logstash Filter - Convert key name from "this_is_example" => 1 to [this][is][example] => 1

鉴于此 LogStash 事件,ruby 哈希

{
    "_some_private_key" => 10,
    "address_unit" => "1",
    "address_sqft" => 1098,
    "address_city" => "NEW YORK",
    "apartment_floor_unit_door" => "5",
    "tags" => [
        "pub",
        "importer",
        "assessment"
    ]
}

应将其存储到 ES 中

{
  "_some_private_key": 10,
  "address": {
    "unit": 1,
    "sqft": 1098,
    "city": "NEW YORK"
  },
  "apartment": {
    "floor" : {
      "unit": {
        doors: 1043
      }
    }
  },
  "tags": [
    "pub",
    "importer",
    "assessment"
  ]
}

限制条件:

我想知道是否有一些 built-in/community 过滤器可以实现它,或者如何使用 ruby 代码实现它。

谢谢!

inp = {
    "address_unit" => "1",
    "address_sqft" => 1098,
    "address_city" => "NEW YORK",
    "tags" => ["pub", "importer", "assessment"]
}

inp.inject({}) do |memo, (k, v)| 
  if k =~ /\A(.*?)_(.*)/
    (memo[$~[1]] ||= {})[$~[2]] = v
  else
    memo[k] = v
  end
  memo
end 

#⇒ {
#  "address" => {
#     "city" => "NEW YORK",
#     "sqft" => 1098,
#     "unit" => "1"
#   },
#     "tags" => [
#    [0] "pub",
#    [1] "importer",
#    [2] "assessment"
#  ]
# }

上面的代码会将所有带下划线的 foo_bar 键分解为嵌套键。

类似于 mudasobwas 的答案,但使用 each_with_object 代替。与 inject 相比,我更喜欢这种方法(each_with_object 仅适用于可变对象,因为您不会 return 在块末尾创建新对象)

def convert(hash)
  hash.each_with_object({}) do |(key, value), akku|
    if (parts = key.split('_')).length == 2
      akku[parts[0]] ||= {}
      akku[parts[0]][parts[1]] = value
    else
      akku[key] = value
    end
  end
end

我也没有使用正则表达式(只是通过 .split() 间接使用),因为我认为这更具可读性)。

是否需要处理带有多个下划线的键?还是更多层级的嵌套?

更新:

def convert(input)
  input.each_with_object({}) do |(key, value), output|
    next if key.start_with?('_')
    keys = key.split('_')
    convert_keys(output, keys, value)
  end
end

def convert_keys(output, keys, value)
  keys[0...-1].each do |key|
    output = output[key] ||= {}
  end
  output[keys.last] = value
end

这应该可以解决问题。它不是递归的(如果输入散列的值再次是带有需要分解的键的散列,则不起作用)因为您的示例输入不需要这样做。 convert_keys 方法也可以递归完成。但我更喜欢这里的迭代方法。

这是否解决了问题?

鉴于您的示例(三个字段),logstash 解决方案如何:

mutate {
    rename => { "address_unit" => "[address][unit]" }
    rename => { "address_sqft" => "[address][sqft]" }
    rename => { "address_city" => "[address][city]" }
}

我没看重命名是否可以一次执行多个操作,所以您也可以试试。