使用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
(因为它隐式地创建regex模式)。他们建议使用
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
字符串
(因为我们正在迭代一个字符数组)。
为什么我们要直接使用char数组?
因为显然
无痛的
不允许
.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]."
}
}
无痛的
?
尽管我在谷歌上快速搜索后找不到任何关于这个名字的历史记录,但从
documentation page
用于生产
.
Groovy
security vulnerabilities
. 因此Elasticsearch团队创建了一个非常有限的Java/Groovy脚本子集,该脚本将具有可预测的性能,并且不包含这些安全漏洞,并将其称为
无痛的
.
如果有什么是真的
脚本语言,是吗
有限的
.