gpt4 book ai didi

elasticsearch - 在 elasticsearch/kibana 脚本字段中将 IP(字符串)转换为 long

转载 作者:行者123 更新时间:2023-11-29 02:51:51 24 4
gpt4 key购买 nike

我在文档中有一个字段是 ipv4 ("1.2.3.4") 的字符串表示形式,该字段的名称是“originating_ip”。我正在尝试使用无痛语言的脚本字段来添加一个新字段 (originating_ip_calc) 以具有所述 IPv4 的 int(长)表示。

以下脚本在 groovy 中工作(据我了解,这基本上应该工作得几乎相同),但在这种特定情况下似乎几乎没有。

​String[] ipAddressInArray = "1.2.3.4".split("\\.");

long result = 0;
for (int i = 0; i < ipAddressInArray.length; i++) {
int power = 3 - i;
int ip = Integer.parseInt(ipAddressInArray[i]);
long longIP = (ip * Math.pow(256, power)).toLong();
result = result + longIP;
}
return result;

我也在找this question正如您从上面的代码中看到的那样,它基于那里的一个答案。

还尝试使用 InetAddress 但没有成功。

最佳答案

借助 Elasticsearch 无痛脚本,您可以使用如下代码:

POST ip_search/doc/_search
{
"query": {
"match_all": {}
},
"script_fields": {
"originating_ip_calc": {
"script": {
"source": """
String ip_addr = params['_source']['originating_ip'];
def ip_chars = ip_addr.toCharArray();
int chars_len = ip_chars.length;
long result = 0;
int cur_power = 0;
int last_dot = chars_len;
for(int i = chars_len -1; i>=-1; i--) {
if (i == -1 || ip_chars[i] == (char) '.' ){
result += (Integer.parseInt(ip_addr.substring(i+ 1, last_dot)) * Math.pow(256, cur_power));
last_dot = i;
cur_power += 1;
}
}
return result
""",
"lang": "painless"
}
}
},
"_source": ["originating_ip"]
}

(请注意,我使用 Kibana console 将请求发送到 ES,它会在发送前进行一些转义以使其成为有效的 JSON。)

这将给出如下响应:

"hits": [
{
"_index": "ip_search",
"_type": "doc",
"_id": "2",
"_score": 1,
"_source": {
"originating_ip": "10.0.0.1"
},
"fields": {
"originating_ip_calc": [
167772161
]
}
},
{
"_index": "ip_search",
"_type": "doc",
"_id": "1",
"_score": 1,
"_source": {
"originating_ip": "1.2.3.4"
},
"fields": {
"originating_ip_calc": [
16909060
]
}
}
]

但为什么一定要这样呢?

为什么 .split 的方法不起作用?

如果您将问题中的代码发送给 ES,它会回复如下错误:

      "script": "String[] ipAddressInArray = \"1.2.3.4\".split(\"\\\\.\");\n\nlong result = 0;\nfor (int i = 0; i < ipAddressInArray.length; i++) {\n    int power = 3 - i;\n    int ip = Integer.parseInt(ipAddressInArray[i]);\n    long longIP = (ip * Math.pow(256, power)).toLong();\n    result = result + longIP;\n}\nreturn result;",
"lang": "painless",
"caused_by": {
"type": "illegal_argument_exception",
"reason": "Unknown call [split] with [1] arguments on type [String]."

这主要是因为Java的String.split() is not considered safe to use (因为它隐式创建了正则表达式模式)。他们建议使用 Pattern#split但要这样做,您应该在索引中启用正则表达式。

默认情况下,它们是禁用的:

      "script": "String[] ipAddressInArray = /\\./.split(\"1.2.3.4\");...
"lang": "painless",
"caused_by": {
"type": "illegal_state_exception",
"reason": "Regexes are disabled. Set [script.painless.regex.enabled] to [true] in elasticsearch.yaml to allow them. Be careful though, regexes break out of Painless's protection against deep recursion and long loops."

为什么我们必须进行显式转换 (char) '.'

因此,我们必须手动将字符串拆分为点。直接的方法是将字符串的每个字符与 '.'(在 Java 中表示 char 文字,而不是 String)进行比较。

但对于painless,它意味着String。所以我们必须对 char 进行显式转换(因为我们正在遍历一个字符数组)。

为什么我们必须直接使用字符数组?

因为显然 painless 也不允许 String.length 方法:

    "reason": {
"type": "script_exception",
"reason": "compile error",
"script_stack": [
"\"1.2.3.4\".length",
" ^---- HERE"
],
"script": "\"1.2.3.4\".length",
"lang": "painless",
"caused_by": {
"type": "illegal_argument_exception",
"reason": "Unknown field [length] for type [String]."
}
}

那为什么叫painless呢?

虽然我在快速谷歌搜索后找不到任何关于命名的历史记录,来自 documentation page和一些经验(如上面的答案)我可以推断它被设计为无痛用于生产

它的前身,Groovy , 由于资源使用和 security vulnerabilities 而成为定时炸弹.因此,Elasticsearch 团队创建了一个非常有限的 Java/Groovy 脚本子集,它具有可预测的性能并且不会包含那些安全漏洞,并将其称为painless

如果关于painless 脚本语言有任何真实之处,那就是它是有限沙盒化

关于elasticsearch - 在 elasticsearch/kibana 脚本字段中将 IP(字符串)转换为 long,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53142440/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com