Elasticsearch Query DSL查詢入門

本篇爲學習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中可以通過以下幾種方法來指定索引

  1. 指定一個固定的索引,ops-coffee-nginx-2019.05.15爲索引名字
GET /ops-coffee-nginx-2019.05.15/_search

以上表示在ops-coffee-nginx-2019.05.15索引下查找數據

  1. 指定多個固定索引,多個索引名字用逗號分割
GET /ops-coffee-nginx-2019.05.15,ops-coffee-nginx-2019.05.14/_search
  1. 用*號匹配,在匹配到的所有索引下查找數據
GET /ops-coffee-nginx-*/_search

當然這裏也可以用逗號分割多個匹配索引

分頁查詢

上邊有說到查詢結果hits默認只展示10個文檔,那我們如何查詢10個以後的文檔呢?ES中給了sizefrom兩個參數

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

最簡單的查詢,下邊的例子就表示查找hostops-coffee.cn的所有記錄

GET /ops-coffee-2019.05.15/_search
{
  "query":{
    "match": {
      "host":"ops-coffee.cn"
    }
  }
}

multi_match

在多個字段上執行相同的match查詢,下邊的例子就表示查詢hosthttp_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小於等於

當使用日期作爲範圍查詢時,我們需要注意下日期的格式,官方支持的日期格式主要有兩種

  1. 時間戳,注意是毫秒粒度
GET /ops-coffee-2019.05.14/_search
{
  "query": {
    "range": {
      "@timestamp": {
        "gte": 1557676800000,
        "lte": 1557680400000,
        "format":"epoch_millis"
      }
    }
  }
}
  1. 日期字符串
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來實現了

例如我們要查詢hostops-coffee.cnhttp_x_forworded_for111.18.78.128status不爲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開始學習,歡迎大家加我好友找我交流,我會非常樂意


相關文章推薦閱讀:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章