Elasticsearch 系列導航
elasticsearch 與 elasticsearch-head 的安裝
ElasticSearch Index API && Mapping
持續更新中
正文
假設你已經有一份數據保存在Elasticsearch里,類似於下面這種schema,如果沒有參考導入測試數據
{ "account_number": 0, "balance": 16623, "firstname": "Bradshaw", "lastname": "Mckenzie", "age": 29, "gender": "F", "address": "244 Columbus Place", "employer": "Euron", "email": "bradshawmckenzie@euron.com", "city": "Hobucken", "state": "CO" }
那么我們接下來就可以 過濾,搜索,聚合來獲取到我們想要的數據。
Elasticsearch提供了一套Json風格的領域特定語言來幫助查詢,被稱為Query DSL.
搜索通過在URL結尾加_search
來指定,具體查詢提交通過Request Body來指定,
比如下面的Request Body:
query: 用來指定查詢條件
from:從第幾個開始取
size:取多少條記錄,默認10條,比如這個例子有13條記錄滿足條件,但是只返回1條記錄
sort:用來指定排序規則
OK,通過剛才的實驗,我們對查詢有了一個基本的認識,下面讓我們來繼續認識更加有趣的查詢:
- 減少返回字段的個數(默認情況下是返回一個文檔的所有字段信息)
{ "query": { "match_all": {} }, "_source": ["account_number", "balance"] }
- 返回account_number等於20的account
{ "query": { "match": { "account_number": 20 } } }
match是一個模糊匹配,但是由於account_number是long類型,所以這里當做精確匹配來過濾
- 返回address字段中包含mill的account
{ "query": { "match": { "address": "mill" } } }
由於address是text類型,所以這里說的是包含mill而不是等於mill.
- 返回address字段中包含"mill" 或 "lane"的account
{ "query": { "match": { "address": "mill lane" } } }
由於address是text類型,而且"mill lane"這里在查詢的時候被當作兩個詞來分別進行查詢
- 返回address字段中包含"mill lane"的account
這里使用match_phrase(短語匹配)查詢類型,把"mill lane"當作一個整體來查詢
{ "query": { "match_phrase": { "address": "mill lane" } } }
- 返回address字段中同時包含"mill" 和 "lane"的account
{ "query": { "bool": { "must": [ { "match": { "address": "mill" } }, { "match": { "address": "lane" } } ] } } }
這里使用了bool查詢語句,它允許我們組合多個小的查詢一起來完成稍微復雜的查詢,
bool must
要求所有子查詢返回true,所有子查詢之間可以理解為一個and的操作。 - 返回address字段中包含"mill" 或 "lane"的account
bool should 要求子查詢中的任一個滿足條件,可以理解為或的關系
{ "query": { "bool": { "should": [ { "match": { "address": "mill" } }, { "match": { "address": "lane" } } ] } } }
- 返回address字段中既不包含"mill" 也不包含 "lane"的account
bool must_not
子句之間是或的關系{ "query": { "bool": { "must_not": [ { "match": { "address": "mill" } }, { "match": { "address": "lane" } } ] } } }
- 返回年齡等於40 且不住在ID地區的account
{ "query": { "bool": { "must": [ { "match": { "age": "40" } } ], "must_not": [ { "match": { "state": "ID" } } ] } } }
我們可以同時聯合must
, should
, and must_not子句在一個bool語句內,
也可以繼續在bool子句下面繼續嵌套使用bool子句來完成更加復雜的查詢需求。
Filter 過濾
在返回的結果中有一個_score字段,score是一個數值,表示查詢條件和這個文檔的相關度,分數越高,說明某個文檔的相關度越高,
反之,相關度越低,但是查詢 並不總是產生分數,尤其當你使用過濾子句來過濾文檔的時候,Elasticsearch會自動檢測這些場景,
自動優化查詢,讓他不要去計算無用的分數,之前我們使用的bool查詢也支持filter子句,
例如我們想獲取賬戶余額大於等於20000 小於等於30000的賬戶信息
{ "query": { "bool": { "must": { "match_all": {} }, "filter": { "range": { "balance": { "gte": 20000, "lte": 30000 } } } } } }
上面的這個例子其實挺好理解的,所有在這個range范圍內的文檔都具有相等的匹配度,
沒有哪一個文檔比其他的文檔匹配度更高,要么在這個范圍內,要么不在,所以相關度是相等的,
就沒有必要再去計算這個score.
Aggregations聚合
聚合允許你給你的數據分組並獲取他們的統計信息,你可以把它和SQL里面的goup by 以及SQL的聚合函數聯系起來,
在Elasticsearch,你可以在一個響應里同時返回聚合信息和結果明細,
比如我們使用state來給所有的accounts分組,默認返回前10條聚合記錄,順序按照組內文檔數量的倒序排列
{ "size": 0, "aggs": { "group_by_state": { "terms": { "field": "state.keyword" } } } }
你可以結合下面的SQL語句更好理解上面的語句
SELECT state, COUNT(*) FROM bank GROUP BY state ORDER BY COUNT(*) DESC
部分返回結果 如下顯示:
{ "took": 29, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits" : { "total" : 1000, "max_score" : 0.0, "hits" : [ ] }, "aggregations" : { "group_by_state" : { "doc_count_error_upper_bound": 20, "sum_other_doc_count": 770, "buckets" : [ { "key" : "ID", "doc_count" : 27 }, { "key" : "TX", "doc_count" : 27 }, { "key" : "AL", "doc_count" : 25 }, { "key" : "MD", "doc_count" : 25 }, { "key" : "TN", "doc_count" : 23 }, { "key" : "MA", "doc_count" : 21 }, { "key" : "NC", "doc_count" : 21 }, { "key" : "ND", "doc_count" : 21 }, { "key" : "ME", "doc_count" : 20 }, { "key" : "MO", "doc_count" : 20 } ] } } }
你可以觀察到,上面的聚合我們設置size=0,不去顯示符合條件的原始記錄,
因為我們這次僅僅需要聚合的結果信息,如果你也需要原始記錄信息,那么你可以重新指定size的大小
下面這個例子我們來求余額的平均值
{ "size": 0, "aggs": { "group_by_state": { "terms": { "field": "state.keyword" }, "aggs": { "average_balance": { "avg": { "field": "balance" } } } } } }
返回如下的結果,可以看到這里我們在group_by_state
里面嵌套使用了average_balance
,這是一種比較通用的做法,
你可以在任意聚合內嵌套任意聚合來獲取需要的統計信息。
下面這個例子演示根據年齡組來分組,然后根據性別來分組最后求賬戶余額的平均值
{ "size": 0, "aggs": { "group_by_age": { "range": { "field": "age", "ranges": [ { "from": 20, "to": 30 }, { "from": 30, "to": 40 }, { "from": 40, "to": 50 } ] }, "aggs": { "group_by_gender": { "terms": { "field": "gender.keyword" }, "aggs": { "average_balance": { "avg": { "field": "balance" } } } } } } } }
下面是年齡組分組 計算聚合的部分返回結果: