Elasticsearch快速入門 第1篇:Elasticsearch入門 Elasticsearch快速入門 第2篇:Elasticsearch和Kibana安裝 Elasticsearch快速入門 第3篇:Elasticsearch索引和文檔操作 Elasticsearch快速入門 第4篇:El ...
- Elasticsearch快速入門 第1篇:Elasticsearch入門
- Elasticsearch快速入門 第2篇:Elasticsearch和Kibana安裝
- Elasticsearch快速入門 第3篇:Elasticsearch索引和文檔操作
- Elasticsearch快速入門 第4篇:Elasticsearch文檔查詢
簡單數據集
到目前為止,已經瞭解了基本知識,現在我們嘗試用更逼真的數據集,這兒已經準備好了一份虛構的JSON,關於客戶銀行賬戶信息的。每個文檔的結構如下:
{ "account_number": 0, "balance": 16623, "firstname": "Bradshaw", "lastname": "Mckenzie", "age": 29, "gender": "F", "address": "244 Columbus Place", "employer": "Euron", "email": "[email protected]", "city": "Hobucken", "state": "CO" }
出於好奇,我從www.json-generator.com/生成了這些數據,請忽略數據的實際值和語義,因為這些都是隨機生成的。
載入樣本數據集
可以從這裡下載示例數據集(accounts.json),解壓到當前目錄,然後用以下方式把它載入到集群中
curl -H "Content-Type: application/json" -XPOST 'localhost:9200/bank/account/_bulk?pretty&refresh' --data-binary "@accounts.json" curl 'localhost:9200/_cat/indices?v'
返回內容如下:
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size yellow open .kibana XYZPR5XGQGWj8YlyZ1et_w 1 1 1 0 3.1kb 3.1kb yellow open bank uoTQIb3GSDOH08CmsIy66A 5 1 999 0 639.5kb 639.5kb
這意味著我們已經成功批量索引999個文檔到bank索引下(類型為account )。
註意,上面的操作不能在kibana中執行,需要使用curl
具體操作是,把下載的json文檔放在和curl.exe相同的目錄,然後打開命令提示符定位到curl.exe所在目錄,然後粘貼以下命令(我的curl版本是7.53.1,需要改成下麵的方式才能執行成功),回車即可
curl -H "Content-Type: application/json" -XPOST localhost:9200/bank/account/_bulk?pretty --data-binary "@accounts.json"
查詢API
運行查詢有兩種方式,一是通過 REST request URI 方式發送查詢參數,二是通過 REST request body 。方式二更為靈活,可以使用可讀性好的JSON 格式定義你的查詢條件,下麵我們針對方式一舉個例子,以後的教程都使用方式二。
REST API的查詢條件放在_search之後,以下例子返回 bank 索引中的所有文檔:
GET /bank/_search?q=*&sort=account_number:asc&pretty
bank 表示查詢bank索引中的文檔, _search 後面跟的是查詢條件,q=* 參數指示 Elasticsearch 匹配索引中的所有文檔。 sort=account_number:asc
參數指示使用 account_number 對結果進行升序排序。 pretty 參數告訴 Elasticsearch 返回漂亮的JSON結果。
返回部分內容如下:
{ "took" : 63, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "failed" : 0 }, "hits" : { "total" : 1000, "max_score" : null, "hits" : [ { "_index" : "bank", "_type" : "account", "_id" : "0", "sort": [0], "_score" : null, "_source" : {"account_number":0,"balance":16623,"firstname":"Bradshaw","lastname":"Mckenzie","age":29,"gender":"F","address":"244 Columbus Place","employer":"Euron","email":"[email protected]","city":"Hobucken","state":"CO"} }, { "_index" : "bank", "_type" : "account", "_id" : "1", "sort": [1], "_score" : null, "_source" : {"account_number":1,"balance":39225,"firstname":"Amber","lastname":"Duke","age":32,"gender":"M","address":"880 Holmes Lane","employer":"Pyrami","email":"[email protected]","city":"Brogan","state":"IL"} }, ... ] } }
至於返回內容,我們看到以下部分:
took
- Elasticsearch 執行查詢的時間(以毫秒為單位)timed_out
- 告訴我們查詢是否超時_shards
- 告訴我們查詢了多少個分片,以及查詢成功/失敗的分片數量hits
- 查詢結果hits.total
- 符合我們查詢條件的文檔總數hits.hits
- 實際查詢結果數組(預設為前10個文檔)hits.sort
- 對結果進行排序的鍵(如果沒提供,則預設使用_score進行排序)hits._score
和max_score
-現在先忽略這些欄位
使用方式二執行上面查詢如下
GET /bank/_search { "query": { "match_all": {} }, "sort": [ { "account_number": "asc" } ] }
不同點是我們用json格式的請求體代替了_search api uri中的q=*參數。我們將會在後面的內容討論json格式的查詢。
註意,當我們接收到返回結果的時候, elasticsearch 已經完全處理了這個請求,不會維護任何的伺服器端的資源或者在結果中打開游標。這與許多其他的平臺形成鮮明的對比(比如sql的游標)
查詢語言介紹
Elasticsearch t提供了一種 JSON-style 的特定領域語言用來執行查詢,稱為 Query DSL,該查詢語言十分全面,初看可能覺得有點嚇人。事實上,學習它的最好方式就是從幾個基本的例子開始。回到上一個例子,我們執行了這個查詢:
GET /bank/_search { "query": { "match_all": {} } }
上面的 query 部分告訴我們查詢定義是什麼, match_all 部分僅僅是我們想運行的查詢的類型,也就是查詢指定索引下的所有文檔。
除了查詢參數以外,也可以通過其他參數影響查詢結果。比如前面的 sort 指定排序欄位,下麵通過 size 指定返回結果數
GET /bank/_search { "query": { "match_all": {} }, "size": 1 }
註意 size 如果不指定,預設是10。
下麵的例子匹配所有,並且返回第11到20之間的文檔
GET /bank/_search { "query": { "match_all": {} }, "from": 10, "size": 10 }
from參數(最小值是0,不是1)指定返迴文檔的起始文檔的索引, size 參數指定一共返回多少個文檔。這個特性對實現分頁非常有用。如果 from 沒有指定,預設值是0。
下麵的例子匹配所有,並且通過 balance 欄位對結果進行降序排序,返回前10條(預設 size )文檔。
GET /bank/_search { "query": { "match_all": {} }, "sort": { "balance": { "order": "desc" } } }
執行查詢
接下來我們進一步探討Query DSL。首先看一下返回的文檔欄位。預設情況下,完整的JSON文檔作為所有搜索的一部分返回。
預設情況下,完整的JSON文檔作為所有搜索的一部分返回。文檔原始內容被稱為源(查詢結果中的_source欄位
)。如果不希望返回整個源文檔,也可以請求僅幾個欄位被返回。
以下示例顯示如何返回兩個欄位(_source內
), account_number 和 balance :
GET /bank/_search { "query": { "match_all": {} }, "_source": ["account_number", "balance"], "size": 1 }
返回內容如下:
{ "took": 3, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 999, "max_score": 1, "hits": [ { "_index": "bank", "_type": "account", "_id": "25", "_score": 1, "_source": { "account_number": 25, "balance": 40540 } } ] } }
以上的例子僅僅減少了 _source 里的欄位,返回的欄位 account_number 和 balance 仍然包含在 _source 中
如果你之前有SQL背景,上述在概念上與SQL SELECT FROM
欄位列表有些相似。
現在來看看查詢部分。通過前面的示例,我們已經學會瞭如何使用 match_all 查詢來匹配所有文檔。現在介紹一個名為match
查詢的新查詢,可以將其視為基本的欄位搜索查詢(即針對特定欄位或一組欄位進行搜索)。
以下示例返回的 account_number 為20:
GET /bank/_search { "query": { "match": { "account_number": 20 } } }
返回結果:
{ "took": 15, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 1, "max_score": 1, "hits": [ { "_index": "bank", "_type": "account", "_id": "20", "_score": 1, "_source": { "account_number": 20, "balance": 16418, "firstname": "Elinor", "lastname": "Ratliff", "age": 36, "gender": "M", "address": "282 Kings Place", "employer": "Scentric", "email": "[email protected]", "city": "Ribera", "state": "WA" } } ] } }
以下實例返回 address 中包含"mill"的所有賬戶:
GET /bank/_search { "query": { "match": { "address": "mill" } } }
以下示例返回address中包含"mill"或者"lane"的所有賬戶:
GET /bank/_search { "query": { "match": { "address": "mill lane" } } }
以下示例是match
(match_phrase
)的一個變體,返回在地址中包含短語"mill lane"的所有帳戶:
GET /bank/_search { "query": { "match_phrase": { "address": "mill lane" } } }
下麵介紹bool
(ean) query 。 布爾
查詢允許我們把多個 match 查詢合併到一個查詢中。
以下示例由兩個 match 查詢組成,返回 address 中既包含"mill" 又包含"lane" 的所有賬戶:
GET /bank/_search { "query": { "bool": { "must": [ { "match": { "address": "mill" } }, { "match": { "address": "lane" } } ] } } }
在上面的示例中, bool must 裡面的所有查詢條件必須都為真時才會被匹配。
相比之下,下麵的示例由兩個match
查詢組成,並返回在地址中包含"mill"或"lane"的所有帳戶:
GET /bank/_search { "query": { "bool": { "should": [ { "match": { "address": "mill" } }, { "match": { "address": "lane" } } ] } } }
在上面的例子中, bool should 子句指定了一個查詢列表,只要其中一個查詢為真,文檔就會被匹配。
以下示例由兩個match
查詢組成,並返回在地址中既不包含"mill"也不包含"lane"的所有帳戶:
GET /bank/_search { "query": { "bool": { "must_not": [ { "match": { "address": "mill" } }, { "match": { "address": "lane" } } ] } } }
在上面的例子中,bool must_not 子句指定一個查詢列表,只有查詢列表中的條件都為假的時候才會被匹配。
也可以把 must,should,must_not 同時組合到bool
子句。此外,我們也可以組合bool
到任何一個bool
子句中,實現複雜的多層bool
子句嵌套邏輯。
下麵的例子返回所有年齡是40歲但不居住在ID(Idaho)的賬戶:
GET /bank/_search { "query": { "bool": { "must": [ { "match": { "age": "40" } } ], "must_not": [ { "match": { "state": "ID" } } ] } } }
執行過濾
前面我們跳過了一點細節,文檔得分(也就是在搜索結果中的 _score 欄位)。分數是一個數值,它是文檔與我們指定的搜索查詢匹配的相對度量。分數越高,文檔越相關,分數越低,文檔的相關性越低。但查詢並不總是需要產生分數,特別是當它們僅用於"過濾"文檔集時。 Elasticsearch 會檢測這些情況,並自動優化查詢執行,以免計算無用的分數。
bool
查詢支持filter子句,它允許你使用一個查詢語句去限制其它子句的匹配結果,同時不會計算文檔的得分。例如,我們來介紹一下
range
query, 它允許我們通過一個範圍值去過濾文檔。通常用於數字或日期過濾。
以下示例使用布爾查詢返回餘額在20000到30000之間(包括端值)的所有帳戶。換句話說,我們想找到餘額大於或等於20000且小於等於30000的賬戶。
GET /bank/_search { "query": { "bool": { "must": { "match_all": {} }, "filter": { "range": { "balance": { "gte": 20000, "lte": 30000 } } } } } }
仔細分析上面的例子,bool
查詢包含了一個match_all
查詢(查詢部分)和一個range
查詢(過濾部分)。我們也可以用任何其它的查詢語句代替查詢和過濾部分的語句。對於上面的例子,因為所有文檔都是指定範圍之內的,他們從某種意義上來說是等價的(equally),即他們的相關度都是一樣的(filter子句查詢,不會改變得分)。
除了 match_all
,match
,bool
,range
查詢,還有很多種類的查詢,但我們不在這裡一一介紹。從現在開始,我們對查詢已經有一個基礎的瞭解,把學到的知識應用到其他查詢類型應該也沒什麼難度。
執行聚合
聚合提供從數據中分組和提取統計信息的功能。理解聚合的最簡單的方法是將其大致等同於SQL GROUP BY和SQL聚合函數。在 Elasticsearch 中,可以返回匹配搜索的同時返回聚合結果,在一個響應中將所有匹配的結果和聚合結果同時返回。這是非常強大和高效的,可以降低網路請求的次數。
以下示例通過state
欄位進行分組,並按照count 降序排序,返回前10(預設值)條數據:
GET /bank/_search { "size": 0, "aggs": { "group_by_state": { "terms": { "field": "state.keyword" } } } }
在SQL中,上述聚合在概念上類似於:
SELECT state, COUNT(*) FROM bank GROUP BY state ORDER BY COUNT(*) DESC
返回內容(僅部分)如下:
{ "took": 50, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 999, "max_score": 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 }, { "