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"
]
}
限制条件:
- 应该绕过以
_
开头的密钥
- 应该是dynamic/recursive,检查关键
apartment_floor_unit_door
例子
我想知道是否有一些 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]" }
}
我没看重命名是否可以一次执行多个操作,所以您也可以试试。
鉴于此 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"
]
}
限制条件:
- 应该绕过以
_
开头的密钥
- 应该是dynamic/recursive,检查关键
apartment_floor_unit_door
例子
我想知道是否有一些 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]" }
}
我没看重命名是否可以一次执行多个操作,所以您也可以试试。