注:本文基于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://stackoverflow.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