脚本化 field 示例
本小节展示了 Kibana 中一些常见场景下的 Lucene expressions 和 Painless 脚本化 field 示例。如上所述,这些示例以来自 Kibana 入门教程的数据集为基础,并且假定你使用的是 Elasticsearch 和 Kibana 5.1.1,因为在之前的版本中,某些类型的脚本化 field 中存在一些与过滤和排序相关的已知问题。
由于 Elasticsearch 5.0 默认启用 Lucene expressions 和 Painless,因此脚本化 fields 在大部分情况下应该都能够开箱即用。唯一例外的是那些需要对 fields 进行基于正则表达式的解析的脚本,这些脚本需要你在 elasticsearch.yml中设置下面的设置,为 Painless 打开正则表达式匹配:
script.painless.regex.enabled: true
对单个 field 执行计算
示例:由字节计算出千字节
语言:expressions
返回类型:数字
doc['bytes'].value / 1024
注意:切记 Kibana 脚本化 fields 一次只能处理一个单独的文档,因此无法在脚本化 fields 中进行时间序列运算。
返回数字的日期运算
示例:将日期解析成小时时间
语言:expressions
返回类型:数字
Lucene expressions 提供了大量开箱即用的 日期处理函数。但是,由于 Lucene expressions 只能返回数字值,因此我们必须使用 Painless 来返回基于字符串的星期值(如下所示)。
doc['@timestamp'].date.hourOfDay
注意:上面的脚本将返回 1-24
doc['@timestamp'].date.dayOfWeek
注意:上面的脚本将返回 1-7
合并两个字符串值
示例:合并源和目标或名字和姓氏
语言:painless
返回类型:字符串
doc['geo.dest.keyword'].value + ':' + doc['geo.src.keyword'].value
注意:由于脚本化 field 需要操作doc_values中的 field,因此我们上面使用的是 .keyword 版本的字符串。
引入逻辑运算
示例:为所有超过 10000 字节的文档返回标签“big download”
语言:painless
返回类型:字符串
if (doc['bytes'].value > 10000) {
return "big download";
}
return "";
注意:引入逻辑运算时,确保每个执行路径都具有良好定义的返回语句和良好定义的返回值(而非 null)。例如,在 Kibana 过滤器中使用上述脚本化 field 时,如果最后没有返回语句或者语句返回 null,都会出现编译错误。另外还请注意,Kibana 脚本化 field 中不支持将逻辑运算分解成函数。
返回子串
示例:返回 URL 中最后一个斜线后面的部分
语言:painless
返回类型:字符串
def path = doc['url.keyword'].value;
if (path != null) {
int lastSlashIndex = path.lastIndexOf('/');
if (lastSlashIndex > 0) {
return path.substring(lastSlashIndex+1);
}
}
return "";
注意:尽量避免使用正则表达式提取子串,因为 indexOf() 操作占用的资源更少,更不易出错。
使用正则表达式匹配字符串,并对匹配进行操作
示例:如果在 field“referer”中找到子串“error”,则返回字符串“error”,否则返回字符串“no error”。
语言:painless
返回类型:字符串
if (doc['referer.keyword'].value =~ /error/) {
return "error"
} else {
return "no error"
}
注意:简化的正则表达式语法对基于正则表达式匹配的条件句有用。
匹配字符串并返回该匹配
示例:返回域,即 field “host”中最后一个点后面的字符串。
语言:painless
返回类型:字符串
def m = /^.*\.([a-z]+)$/.matcher(doc['host.keyword'].value);
if ( m.matches() ) {
return m.group(1)
} else {
return "no match"
}
注意:通过正则表达式 matcher() 函数定义对象,可以提取与正则表达式相匹配的字符组并将它们返回。
匹配数字并返回该匹配
示例:返回 IP 地址的第一个八位组(存储为字符串)并将它视为一个数字。
语言:painless
返回类型:数字
def m = /^([0-9]+)\..*$/.matcher(doc['clientip.keyword'].value);
if ( m.matches() ) {
return Integer.parseInt(m.group(1))
} else {
return 0
}
注意:在脚本中返回正确的数据类型是很重要的。正则表达式匹配返回的是字符串,即便匹配的是数字依然返回字符串,因此返回时应该显式地将它转换成整数。
返回字符串的日期运算
示例:将日期解析成星期值再解析成字符串
语言:painless
返回类型:字符串
LocalDateTime.ofInstant(Instant.ofEpochMilli(doc['@timestamp'].value), ZoneId.of('Z')).getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.getDefault())
注意:由于 Painless 支持 Java 所有的原生类型,因此通过它可以获取与这些类型相关的原生函数,例如 LocalDateTime(),这在执行更加高级的日期运算时有用。