本篇為學習DSL時做的筆記,適合ES新手,大佬請略過~
Query DSL又叫查詢表示式,是一種非常靈活又富有表現力的查詢語言,採用JSON介面的方式實現豐富的查詢,並使你的查詢語句更靈活、更精確、更易讀且易除錯
查詢與過濾
Elasticsearch(以下簡稱ES)中的資料檢索分為兩種情況:查詢和過濾。
Query查詢會對檢索結果進行評分,注重的點是匹配程度,例如檢索“運維咖啡吧”與文件的標題有多匹配,計算的是查詢與文件的相關程度,計算完成之後會算出一個評分,記錄在_score
欄位中,並最終按照_score
欄位來對所有檢索到的文件進行排序
Filter過濾不會對檢索結果進行評分,注重的點是是否匹配,例如檢索“運維咖啡吧”是否匹配文件的標題,結果只有匹配或者不匹配,因為只是對結果進行簡單的匹配,所以計算起來也非常快,並且過濾的結果會被快取到記憶體中,效能要比Query查詢高很多
簡單查詢
一個最簡單的DSL查詢表示式如下:
GET /_search
{
"query":{
"match_all": {}
}
}
**/_search** 查詢整個ES中所有索引的內容
query 為查詢關鍵字,類似的還有aggs
為聚合關鍵字
match_all 匹配所有的文件,也可以寫match_none
不匹配任何文件
返回結果:
{
"took": 6729,
"timed_out": false,
"num_reduce_phases": 6,
"_shards": {
"total": 2611,
"successful": 2611,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 7662397664,
"max_score": 1,
"hits": [
{
"_index": ".kibana",
"_type": "doc",
"_id": "url:ec540365d822e8955cf2fa085db189c2",
"_score": 1,
"_source": {
"type": "url",
"updated_at": "2018-05-09T07:19:46.075Z",
"url": {
"url": "/app/kibana",
"accessCount": 0,
"createDate": "2018-05-09T07:19:46.075Z",
"accessDate": "2018-05-09T07:19:46.075Z"
}
}
},
...省略其他的結果...
]
}
}
took: 表示我們執行整個搜尋請求消耗了多少毫秒
timed_out: 表示本次查詢是否超時
這裡需要注意當timed_out
為True時也會返回結果,這個結果是在請求超時時ES已經獲取到的資料,所以返回的這個資料可能不完整。
且當你收到timed_out
為True之後,雖然這個連線已經關閉,但在後臺這個查詢並沒有結束,而是會繼續執行
**_shards:** 顯示查詢中參與的分片資訊,成功多少分片失敗多少分片等
hits: 匹配到的文件的資訊,其中total
表示匹配到的文件總數,max_score
為文件中所有_score
的最大值
hits中的hits
陣列為查詢到的文件結果,預設包含查詢結果的前十個文件,每個文件都包含文件的_index
、_type
、_id
、_score
和_source
資料
結果文件預設情況下是按照相關度(_score)進行降序排列,也就是說最先返回的是相關度最高的文件,文件相關度意思是文件內容與查詢條件的匹配程度,上邊的查詢與過濾中有介紹
指定索引
上邊的查詢會搜尋ES中的所有索引,但我們通常情況下,只需要去固定一個或幾個索引中搜尋就可以了,搜尋全部無疑會造成資源的浪費,在ES中可以通過以下幾種方法來指定索引
- 指定一個固定的索引,
ops-coffee-nginx-2019.05.15
為索引名字
GET /ops-coffee-nginx-2019.05.15/_search
以上表示在ops-coffee-nginx-2019.05.15
索引下查詢資料
- 指定多個固定索引,多個索引名字用逗號分割
GET /ops-coffee-nginx-2019.05.15,ops-coffee-nginx-2019.05.14/_search
- 用*號匹配,在匹配到的所有索引下查詢資料
GET /ops-coffee-nginx-*/_search
當然這裡也可以用逗號分割多個匹配索引
分頁查詢
上邊有說到查詢結果hits
預設只展示10個文件,那我們如何查詢10個以後的文件呢?ES中給了size
和from
兩個引數
size: 設定一次返回的結果數量,也就是hits
中的文件數量,預設為10
from: 設定從第幾個結果開始往後查詢,預設值為0
GET /ops-coffee-nginx-2019.05.15/_search
{
"size": 5,
"from": 10,
"query":{
"match_all": {}
}
}
以上查詢就表示查詢ops-coffee-nginx-2019.05.15
索引下的所有資料,並會在hits
中顯示第11到第15個文件的資料
全文查詢
上邊有用到一個match_all
的全文查詢關鍵字,match_all
為查詢所有記錄,常用的查詢關鍵字在ES中還有以下幾個
match
最簡單的查詢,下邊的例子就表示查詢host
為ops-coffee.cn
的所有記錄
GET /ops-coffee-2019.05.15/_search
{
"query":{
"match": {
"host":"ops-coffee.cn"
}
}
}
multi_match
在多個欄位上執行相同的match查詢,下邊的例子就表示查詢host
或http_referer
欄位中包含ops-coffee.cn
的記錄
GET /ops-coffee-2019.05.15/_search
{
"query":{
"multi_match": {
"query":"ops-coffee.cn",
"fields":["host","http_referer"]
}
}
}
query_string
可以在查詢裡邊使用AND或者OR來完成複雜的查詢,例如:
GET /ops-coffee-2019.05.15/_search
{
"query":{
"query_string": {
"query":"(a.ops-coffee.cn) OR (b.ops-coffee.cn)",
"fields":["host"]
}
}
}
以上表示查詢host為a.ops-coffee.cn
或者b.ops-coffee.cn
的所有記錄
也可以用下邊這種方式組合更多的條件完成更復雜的查詢請求
GET /ops-coffee-2019.05.14/_search
{
"query":{
"query_string": {
"query":"host:a.ops-coffee.cn OR (host:b.ops-coffee.cn AND status:403)"
}
}
}
以上表示查詢(host為a.ops-coffee.cn
)或者是(host為b.ops-coffee.cn
且status為403)的所有記錄
與其像類似的還有個simple_query_string的關鍵字,可以將query_string
中的AND或OR用+
或|
這樣的符號替換掉
term
term可以用來精確匹配,精確匹配的值可以是數字、時間、布林值或者是設定了not_analyzed
不分詞的字串
GET /ops-coffee-2019.05.14/_search
{
"query":{
"term": {
"status": {
"value": 404
}
}
}
}
term對輸入的文字不進行分析,直接精確匹配輸出結果,如果要同時匹配多個值可以使用terms
GET /ops-coffee-2019.05.14/_search
{
"query": {
"terms": {
"status":[403,404]
}
}
}
range
range用來查詢落在指定區間內的數字或者時間
GET /ops-coffee-2019.05.14/_search
{
"query": {
"range":{
"status":{
"gte": 400,
"lte": 599
}
}
}
}
以上表示搜尋所有狀態為400到599之間的資料,這裡的操作符主要有四個gt
大於,gte
大於等於,lt
小於,lte
小於等於
當使用日期作為範圍查詢時,我們需要注意下日期的格式,官方支援的日期格式主要有兩種
- 時間戳,注意是毫秒粒度
GET /ops-coffee-2019.05.14/_search
{
"query": {
"range": {
"@timestamp": {
"gte": 1557676800000,
"lte": 1557680400000,
"format":"epoch_millis"
}
}
}
}
- 日期字串
GET /ops-coffee-2019.05.14/_search
{
"query": {
"range":{
"@timestamp":{
"gte": "2019-05-13 18:30:00",
"lte": "2019-05-14",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd",
"time_zone": "+08:00"
}
}
}
}
通常更推薦用這種日期字串的方式,看起來比較清晰,日期格式可以按照自己的習慣輸入,只需要format
欄位指定匹配的格式,如果格式有多個就用||
分開,像例子中那樣,不過我更推薦用同樣的日期格式
如果日期中缺少年月日這些內容,那麼缺少的部分會用unix的開始時間(即1970年1月1日)填充,當你將"format":"dd"
指定為格式時,那麼"gte":10
將被轉換成1970-01-10T00:00:00.000Z
elasticsearch中預設使用的是UTC時間,所以我們在使用時要通過time_zone
來設定好時區,以免出錯
組合查詢
通常我們可能需要將很多個條件組合在一起查出最後的結果,這個時候就需要使用ES提供的bool
來實現了
例如我們要查詢host
為ops-coffee.cn
且http_x_forworded_for
為111.18.78.128
且status
不為200的所有資料就可以使用下邊的語句
GET /ops-coffee-2019.05.14/_search
{
"query":{
"bool": {
"filter": [
{"match": {
"host": "ops-coffee.cn"
}},
{"match": {
"http_x_forwarded_for": "111.18.78.128"
}}
],
"must_not": {
"match": {
"status": 200
}
}
}
}
}
主要有四個關鍵字來組合查詢之間的關係,分別為:
must: 類似於SQL中的AND,必須包含
must_not: 類似於SQL中的NOT,必須不包含
should: 滿足這些條件中的任何條件都會增加評分_score
,不滿足也不影響,should
只會影響查詢結果的_score
值,並不會影響結果的內容
filter: 與must相似,但不會對結果進行相關性評分_score
,大多數情況下我們對於日誌的需求都無相關性的要求,所以建議查詢的過程中多用filter
寫在最後
ES的查詢博大精深,本篇文章屬於基礎入門,內容來源於官網
網上關於ELK搭建部署日誌收集的文章很多,但收集到日誌之後該如何應用這個資料寶庫呢?網上僅有一些大廠分享的比較泛的概念沒有實際落地的過程,我在想把這些資料利用起來,初步想法是去ES搜尋出來業務或者功能的流量資料,然後做趨勢分析,這不從DSL開始學習,歡迎大家加我好友找我交流,我會非常樂意
相關文章推薦閱讀: