注:本文基于Kibana 7.13.4版本
1. 背景
在上一篇文章——Kibana常用搜索语法,我们简单介绍了kibana的常用搜索语法,但在实际使用中,总是出现各种异常,为什么明明存在的字符串就是匹配不到,搜不出来,今天我们就来稍微深入下Kibana的搜索原理。
2. 关于Kibana的正则表达式
因为Kibana的正则表达式引擎并不是使用perl pcre,因此有一些正则并不支持,比如开头和结尾锚定符号,^和$,详细的支持符号可以查看官方文档,https://www.elastic.co/guide/en/elasticsearch/reference/7.13/regexp-syntax.html
3. 数据字段类型
我们的日志,每个字段都有对应的数据类型,而不同的数据类型也决定了该字段的搜索属性,比如是否允许全文搜索。关于Kibana支持的数据类型可以参考官方文档,https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html。
我们今天主要来看下text类型和keyword类型,这两个类型也是导致我们搜索结果不符合预期的主要原因。
-
keyword
保留字段原格式,不进行解析,搜索时需要匹配到整个字段,比如对于一个字段为"how are you",你无法用how或者are来搜索,只能用完整的“how are you”来搜索,或者使用正则和通配符,比如how* -
text
可以被分析,也就是能支持全文搜索,比如对于一个字段为"how are you",它就会被解析为
“how” "are" "you"
那我们搜索时,就可以通过这三个词中的任意一个来搜索
4. mapping
既然每个字段都有对应的类型,那如何确定或者如何设置某个字段的类型呢,这就需要通过mapping。所谓mapping就是将传入的日志通过一定规则将每个字段映射成对应的类型。而这个规则就是我们需要关注的。
我们可以通过Kibana的Dev Tools来创建index并设置对应的mapping规则,
PUT mytest
{
"mappings": {
"properties": {
"message1": {
"type": "text"
},
"message2": {
"type": "keyword"
}
}
}
}
如上,我们定义了新的index为mytest,有两个字段,分别是text类型的message1和keyword类型的message2。对于已存在的index,我们可以通过get方式获取详细的mapping规则,
GET /mytest/_mapping
5. analyze
上面我们说到,对于text类型的字段是可解析的,可以被全文搜索,那我们又如何来确定这个全文搜索的最小粒度呢。比如“how are you”这个文本我们很好理解,最小粒度就是一个单词。但如果对于复杂一些的字符串呢,比如“/var/log/yum.log”。这就涉及到分词,也就是对字符串的解析。Kibana默认的分析器为standard analyzer,其遵循的分词规范为Unicode® Standard Annex #29,具体规则我们不细说。我们主要是关注分词的结果,同样可以通过Kibana的Dev Tools来测试。
可以通过以下方式获取指定文本的解析分词结果,用GET请求也一样。
POST _analyze
{
"analyzer": "standard",
"text": "/var/log/yum.log"
}
有结果可知,这个文本被分为三部分,所以我们搜索该文本时,应该用yum.log,而不是yum,否则就搜索不到
6. 简单实践
说完这些,我们通过一个小例子来说明,这样理解起来比较直接。需要注意的是,以下测试都是在Lucene开启的情况下测试。
首先我们以第四部分的mapping为例子,创建mytest索引和mapping规则,然后我们创建几条数据,用于接下来的测试,
PUT mytest/_doc/1?refresh
{
"message1": "hello world",
"message2":"how are you"
}
PUT mytest/_doc/2?refresh
{
"message1": "how are you",
"message2":"hello world"
}
PUT mytest/_doc/3?refresh
{
"message1": "/var/log/yum.log",
"message2":"path"
}
然后我们创建index pattern,把mytest导入,就能看到这三条文档,
这样我们就可以开始我们的测试了。
- text
message1:helloworld #返回第一条文档
message1:hello #无文档返回
message1:how #返回第二条文档
message1:are #返回第二条文档
message1:var #返回第三条文档
message1:yum.log #返回第三条文档
message1:yum #无文档返回
message1:yum* #返回第三条文档
- keyword
message2:"how are you" #返回第一条文档
message2:how #无文档返回
message2:how* #返回第一条文档
message2:are* #无文档返回
message2:*are* #返回第一条文档
message2:helloworld #返回第二条文档
参考文档:
- https://*.com/questions/52908780/kibana-using-regex-doesnt-work-as-expected
- https://www.elastic.co/guide/en/elasticsearch/reference/7.13/regexp-syntax.html
- https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html
- https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-analyze.html