既然咱們已經瞭解了基礎知識,讓咱們來嘗試操做一些更真實的數據集。我已經預先準備好了一些虛擬的顧客銀行帳戶信息JSON文檔樣本。每個文檔都有以下的機構:html
{ "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" }
出於好奇,這些數據是在www.json-generator.com生成的。全部請忽略這些數據值的實際意義,由於它們都是隨機生成的。git
你能夠從這裏下載樣本數據集(accounts.json)。把它放到咱們當前的目錄下,而後使用以下的命令把它加載到咱們得集羣中:github
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 bank l7sSYV2cQXmu6_4rJWVIww 5 1 1000 0 128.6kb 128.6kb
這意味着咱們剛剛成功將1000個文檔批量放入bank索引中(在account類型下)。json
如今,讓咱們從一些簡單的搜索指令開始。執行搜索有兩種基礎的方式,一種是在請求的URL中加入參數來實現,另外一種方式是將請求內容放到請求體中。使用請求體可讓你的JSON數據以一種更加可讀和更加富有展示力的方式發送。咱們將會在一開始演示一次使用請求URI的方式,而後在本教程剩餘的部分,咱們將統一使用請求體的方式發送。api
REST API可使用_search
端點來實現搜索。以下的示例將返回bank索引的全部的文檔:數組
HTTP請求:服務器
GET /bank/_search?q=*&sort=account_number:asc&pretty
Curl命令:網絡
curl -XGET 'localhost:9200/bank/_search?q=*&sort=account_number:asc&pretty&pretty'
Kibana Console:app
http://localhost:5601/app/kibana#/dev_tools/console?load_from=https://www.elastic.co/guide/en/elasticsearch/reference/current/snippets/_the_search_api/1.json
讓咱們首先來詳細分析一下這個搜索請求。這個請求在bank索引中進行搜索(使用 _search
端點),而後 q=*
參數命令Elasticsearch匹配索引中的所有文檔。sort=account_number:asc
參數表示按 account_number
屬性升序排列返回的結果。pretty
參數以前已經提到過,就是將返回結果以美觀的格式返回。
返回結果爲(展現部分):
{ "took" : 63, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "skipped" : 0, "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":"bradshawmckenzie@euron.com","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":"amberduke@pyrami.com","city":"Brogan","state":"IL"} }, ... ] } }
關於返回結果,咱們看到了以下的部分:
took
- Elasticsearch執行這次搜索所用的時間(單位:毫秒)timed_out
- 告訴咱們這次搜索是否超時_shards
- 告訴咱們搜索了多少分片,還有搜索成功和搜索失敗的分片數量hits
- 搜索結果hits.total
- 符合搜索條件的文檔數量hits.hits
- 實際返回的搜索結果對象數組(默認只返回前10條)hits.sort
- 返回結果的排序字段值(若是是按score進行排序,則沒有)hits._score
和 max_score
- 目前先忽略這兩個字段以下是相同效果的另外一種將數據放入請求體的方式:
HTTP請求內容:
GET /bank/_search { "query": { "match_all": {} }, "sort": [ { "account_number": "asc" } ] }
curl命令:
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d' { "query": { "match_all": {} }, "sort": [ { "account_number": "asc" } ] } '
Kibana Console:
http://localhost:5601/app/kibana#/dev_tools/console?load_from=https://www.elastic.co/guide/en/elasticsearch/reference/current/snippets/_the_search_api/2.json
這裏的不一樣點在於咱們使用一個JSON格式的請求體代替了在URI中的 q=*
參數。咱們將在下一節詳細討論這種JSON格式的查詢方式。
一旦你獲得了返回結果,Elasticsearch就徹底執行結束,不會保持任何的服務器資源或者往你的結果里加入開放的遊標,理解這一點是很是重要的。這同狠多其餘的平臺好比SQL數據庫的一些特性造成了鮮明的對比,好比在SQL數據庫中你可能在查詢時,會首先獲得查詢結果的一部分,而後你須要經過一些有狀態的服務端遊標不斷地去請求服務端來取得剩餘的查詢結果。
Elasticsearch提供了一種JSON格式的領域特定語言,你可使用它來執行查詢。這個一般叫作Query DSL。這門查詢語言至關的全面以致於你第一次看到它時會被它嚇住,不過學習它最好的方式就是從一些簡單的示例程序開始。
回到咱們上個例子,咱們執行了這個查詢:
HTTP請求內容:
GET /bank/_search { "query": { "match_all": {} } }
curl命令:
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d' { "query": { "match_all": {} } } '
Kibana Console:
http://localhost:5601/app/kibana#/dev_tools/console?load_from=https://www.elastic.co/guide/en/elasticsearch/reference/current/snippets/_introducing_the_query_language/1.json
分析以上查詢,query
部分告訴咱們咱們的查詢定義是什麼,match_all
部分簡單指定了咱們想去執行的查詢類型,意思就是在索引中搜索全部的文檔。
除了query
參數,咱們還能夠經過其餘的參數影響搜索結果。在上一節的示例中咱們使用了sort
來指定搜索結果的順序,這裏咱們指定size
來指定返回的結果數量:
HTTP請求內容:
GET /bank/_search { "query": { "match_all": {} }, "size": 1 }
curl命令:
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d' { "query": { "match_all": {} }, "size": 1 } '
Kibana Console:
http://localhost:5601/app/kibana#/dev_tools/console?load_from=https://www.elastic.co/guide/en/elasticsearch/reference/current/snippets/_introducing_the_query_language/2.json
注意若是size
沒有指定,它默認爲10。
以下的示例使用match_all
並返回了11到20的文檔:
HTTP請求內容:
GET /bank/_search { "query": { "match_all": {} }, "from": 10, "size": 10 }
curl命令:
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d' { "query": { "match_all": {} }, "from": 10, "size": 10 } '
Kibana Console:
http://localhost:5601/app/kibana#/dev_tools/console?load_from=https://www.elastic.co/guide/en/elasticsearch/reference/current/snippets/_introducing_the_query_language/3.json
from
參數(從0開始)指定了從哪一個文檔索引開始,size
參數指定了從from
指定的索引開始返回多少個文檔。這個特性在實現分頁搜索時頗有用。注意若是from
參數沒有指定,它默認爲0。
以下示例使用match_all
而且按帳戶的balance值進行倒序排列後返回前10條文檔:
HTTP請求內容:
GET /bank/_search { "query": { "match_all": {} }, "sort": { "balance": { "order": "desc" } } }
curl命令:
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d' { "query": { "match_all": {} }, "sort": { "balance": { "order": "desc" } } } '
Kibana Console:
http://localhost:5601/app/kibana#/dev_tools/console?load_from=https://www.elastic.co/guide/en/elasticsearch/reference/current/snippets/_introducing_the_query_language/4.json
既然咱們已經瞭解了一些基礎的搜索參數,那就讓咱們來深刻學習一下Query DSL吧。首先,咱們來關注一下返回的文檔屬性。默認狀況下,文檔會做爲搜索結果的一部分返回全部的屬性值。這個文檔的JSON內容被稱爲source(返回結果中的hits的_source屬性值)。若是咱們不須要返回全部的source文檔屬性,咱們能夠在請求體中加入咱們須要返回的屬性名。
以下的示例演示瞭如何返回兩個屬性,account_number
和 balance
(在_source
中):
HTTP請求內容:
GET /bank/_search { "query": { "match_all": {} }, "_source": ["account_number", "balance"] }
curl命令:
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d' { "query": { "match_all": {} }, "_source": ["account_number", "balance"] } '
Kibana Console:
http://localhost:5601/app/kibana#/dev_tools/console?load_from=https://www.elastic.co/guide/en/elasticsearch/reference/current/snippets/_executing_searches/1.json
注意上面的例子僅僅只是減小了_source
裏的屬性。它仍然會返回_source
屬性,只不過_source
屬性中之包含account_number
和balance
兩個屬性。
若是你以前學過SQL,上面的示例有點像SQL中的SELECT
FROM
中指定返回的字段列表。
如今,讓咱們的視線轉到查詢部分。以前咱們已經看到如何使用match_all
來匹配全部的文檔。如今讓咱們介紹一個新的查詢叫作match
查詢,它能夠被認爲是基本的屬性搜索查詢(就是經過特定的一個或多個屬性來搜索)。
以下的示例返回account_number爲20的文檔:
HTTP請求內容:
GET /bank/_search { "query": { "match": { "account_number": 20 } } }
curl命令:
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d' { "query": { "match": { "account_number": 20 } } } '
Kibana Console:
http://localhost:5601/app/kibana#/dev_tools/console?load_from=https://www.elastic.co/guide/en/elasticsearch/reference/current/snippets/_executing_searches/2.json
以下示例返回全部的address字段中包含「mill」這個單詞的帳戶文檔:
HTTP請求內容:
GET /bank/_search { "query": { "match": { "address": "mill" } } }
curl命令:
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d' { "query": { "match": { "address": "mill" } } } '
Kibana Console:
http://localhost:5601/app/kibana#/dev_tools/console?load_from=https://www.elastic.co/guide/en/elasticsearch/reference/current/snippets/_executing_searches/3.json
以下示例返回全部的address字段中包含「mill」或者是「lane」的帳戶文檔:
HTTP請求內容:
GET /bank/_search { "query": { "match": { "address": "mill lane" } } }
curl命令:
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d' { "query": { "match": { "address": "mill lane" } } } '
Kibana Console:
http://localhost:5601/app/kibana#/dev_tools/console?load_from=https://www.elastic.co/guide/en/elasticsearch/reference/current/snippets/_executing_searches/4.json
以下示例是match
的一種變體(match_phrase
),這個將返回全部address中包含「mill lane」這個短語的帳戶文檔:
HTTP請求內容:
GET /bank/_search { "query": { "match_phrase": { "address": "mill lane" } } }
curl命令:
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d' { "query": { "match_phrase": { "address": "mill lane" } } } '
Kibana Console:
http://localhost:5601/app/kibana#/dev_tools/console?load_from=https://www.elastic.co/guide/en/elasticsearch/reference/current/snippets/_executing_searches/5.json
如今讓咱們介紹 bool
查詢。bool
查詢容許咱們使用布爾邏輯將小的查詢組成大的查詢。
以下的示例組合兩個match
查詢而且返回全部address屬性中包含 「mill」 和 「lane」 的帳戶文檔:
HTTP請求內容:
GET /bank/_search { "query": { "bool": { "must": [ { "match": { "address": "mill" } }, { "match": { "address": "lane" } } ] } } }
curl命令:
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d' { "query": { "bool": { "must": [ { "match": { "address": "mill" } }, { "match": { "address": "lane" } } ] } } } '
Kibana Console:
http://localhost:5601/app/kibana#/dev_tools/console?load_from=https://www.elastic.co/guide/en/elasticsearch/reference/current/snippets/_executing_searches/6.json
在上述示例中,bool
must
子句指定了全部匹配文檔必須知足的條件。
相比之下,以下的示例組合兩個match
查詢而且返回全部address屬性中包含 「mill」 或 「lane」 的帳戶文檔:
HTTP請求內容:
GET /bank/_search { "query": { "bool": { "should": [ { "match": { "address": "mill" } }, { "match": { "address": "lane" } } ] } } }
curl命令:
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d' { "query": { "bool": { "should": [ { "match": { "address": "mill" } }, { "match": { "address": "lane" } } ] } } } '
Kibana Console:
http://localhost:5601/app/kibana#/dev_tools/console?load_from=https://www.elastic.co/guide/en/elasticsearch/reference/current/snippets/_executing_searches/7.json
在上述的例子中,bool
should
子句指定了匹配文檔只要知足其中的任何一個條件便可匹配。
以下示例組合兩個match
查詢而且返回全部address屬性中既不包含 「mill」 也不包含 「lane」 的帳戶文檔:
HTTP請求內容:
GET /bank/_search { "query": { "bool": { "must_not": [ { "match": { "address": "mill" } }, { "match": { "address": "lane" } } ] } } }
curl命令:
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d' { "query": { "bool": { "must_not": [ { "match": { "address": "mill" } }, { "match": { "address": "lane" } } ] } } } '
Kibana Console:
http://localhost:5601/app/kibana#/dev_tools/console?load_from=https://www.elastic.co/guide/en/elasticsearch/reference/current/snippets/_executing_searches/8.json
在上述例子中,bool
must_not
子句指定了其中的任何一個條件都不知足時便可匹配。
咱們能夠在一個bool
查詢中同時指定must
,should
和must_not
子句。此外,咱們也能夠在一個bool
子句中組合另外一個bool
來模擬任何複雜的多重布爾邏輯。
以下的示例返回全部age屬性爲40,而且state屬性不爲ID的帳戶文檔:
HTTP請求內容:
GET /bank/_search { "query": { "bool": { "must": [ { "match": { "age": "40" } } ], "must_not": [ { "match": { "state": "ID" } } ] } } }
curl命令:
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d' { "query": { "bool": { "must": [ { "match": { "age": "40" } } ], "must_not": [ { "match": { "state": "ID" } } ] } } } '
Kibana Console:
http://localhost:5601/app/kibana#/dev_tools/console?load_from=https://www.elastic.co/guide/en/elasticsearch/reference/current/snippets/_executing_searches/9.json
在以前的章節中,咱們跳過了一個叫作文檔得分(在搜索結果中的_score
屬性)的小細節。這個得分是一個數值,它是一個相對量,用來衡量搜索結果跟咱們指定的關鍵字的相關程度。分數越高,說明這個文檔的相關性越大,分數越低,說明這個文檔的相關性越小。
可是一些查詢結果並不老是須要產生得分,尤爲是當他們僅僅被用來過濾文檔集的時候。Elasticsearch會檢測這種狀況並自動優化查詢以避免計算無用的分數。
咱們在前面章節介紹的bool
查詢也支持 filter
子句,它容許咱們能夠在不改變得分計算邏輯的的狀況下限制其餘子句匹配的查詢結果。爲了示例說明,讓咱們介紹一下range
查詢,它容許咱們經過一個值區間來過濾文檔。這個一般用在數值和日期過濾上。
以下的示例使用bool查詢返回全部餘額在20000到30000之間的帳戶(包含邊界)。換句話說,咱們想查詢帳戶餘額大於等於20000而且小於等於30000的用戶。
HTTP請求內容:
GET /bank/_search { "query": { "bool": { "must": { "match_all": {} }, "filter": { "range": { "balance": { "gte": 20000, "lte": 30000 } } } } } }
curl命令:
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d' { "query": { "bool": { "must": { "match_all": {} }, "filter": { "range": { "balance": { "gte": 20000, "lte": 30000 } } } } } } '
Kibana Console:
http://localhost:5601/app/kibana#/dev_tools/console?load_from=https://www.elastic.co/guide/en/elasticsearch/reference/current/snippets/_executing_filters/1.json
仔細分析一下上面的例子,bool查詢在查詢部分使用match_all
,在過濾部分使用range
。咱們可使用任何的查詢來代替查詢部分和過濾部分。在上面的例子中,range查詢讓結果更加合乎情理,由於文檔在這個區間中必定是符合的,就是說,沒有比這些相關性更大的了。
除了match_all
,match
,bool
,和range
查詢以外,還有不少其餘的查詢類型,在這裏咱們就不一一介紹了。當咱們對這些基礎的理解了以後,再去學習和使用其餘的查詢類型應該是不會太難了。
聚合提供了功能能夠分組並統計你的數據。理解聚合最簡單的方式就是能夠把它粗略的看作SQL的GROUP BY操做和SQL的聚合函數。在Elasticsearch中,你能夠在執行搜索後在一個返回結果中同時返回搜索結果和聚合結果。你可使用簡潔的API執行搜索和多個聚合操做,而且能夠一次拿到全部的結果,避免網絡切換,就此而言,這是一個很是強大和高效功能。
做爲開始,以下的例子將帳戶按state進行分組,而後按count降序(默認)返回前10組(默認)states。
HTTP請求內容:
GET /bank/_search { "size": 0, "aggs": { "group_by_state": { "terms": { "field": "state.keyword" } } } }
curl命令:
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d' { "size": 0, "aggs": { "group_by_state": { "terms": { "field": "state.keyword" } } } } '
Kibana Console:
http://localhost:5601/app/kibana#/dev_tools/console?load_from=https://www.elastic.co/guide/en/elasticsearch/reference/current/snippets/_executing_aggregations/1.json
上面的聚合的例子跟以下的SQL相似:
SELECT state, COUNT(*) FROM bank GROUP BY state ORDER BY COUNT(*) DESC
返回結果爲(展現部分):
{ "took": 29, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped" : 0, "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 } ] } } }
咱們能夠看到有27個帳戶在ID
(愛達荷州),而後27個在TX
(得克薩斯州),還有25個在AL
(亞拉巴馬州),等等。
注意咱們設置了size=0
來不顯示hits搜索結果,由於咱們這裏只關心聚合結果。
以下示例咱們在上一個聚合的基礎上構建,這個示例計算每一個state分組的平均帳戶餘額(仍是使用默認按count倒序返回前10個):
HTTP請求內容:
GET /bank/_search { "size": 0, "aggs": { "group_by_state": { "terms": { "field": "state.keyword" }, "aggs": { "average_balance": { "avg": { "field": "balance" } } } } } }
curl命令:
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d' { "size": 0, "aggs": { "group_by_state": { "terms": { "field": "state.keyword" }, "aggs": { "average_balance": { "avg": { "field": "balance" } } } } } } '
Kibana Console:
http://localhost:5601/app/kibana#/dev_tools/console?load_from=https://www.elastic.co/guide/en/elasticsearch/reference/current/snippets/_executing_aggregations/2.json
注意咱們是怎麼嵌套average_balance
聚合到group_by_state
聚合中的。
這是一個適用於全部聚合操做的通用模式。你能夠任意嵌套聚合,從你的數據中提取你須要的主題彙總。
以下例子依然是在以前的聚合上構建,咱們如今來按平均餘額倒序排列:
HTTP請求內容:
GET /bank/_search { "size": 0, "aggs": { "group_by_state": { "terms": { "field": "state.keyword", "order": { "average_balance": "desc" } }, "aggs": { "average_balance": { "avg": { "field": "balance" } } } } } }
curl命令:
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d' { "size": 0, "aggs": { "group_by_state": { "terms": { "field": "state.keyword", "order": { "average_balance": "desc" } }, "aggs": { "average_balance": { "avg": { "field": "balance" } } } } } } '
Kibana Console:
http://localhost:5601/app/kibana#/dev_tools/console?load_from=https://www.elastic.co/guide/en/elasticsearch/reference/current/snippets/_executing_aggregations/3.json
以下示例演示咱們如何按年齡區間分組(20-29,30-39,40-49),而後按性別,最後獲取每一個年齡區間,每一個性別的平均帳戶餘額:
HTTP請求內容:
GET /bank/_search { "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" } } } } } } } }
curl命令:
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d' { "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" } } } } } } } } '
Kibana Console:
http://localhost:5601/app/kibana#/dev_tools/console?load_from=https://www.elastic.co/guide/en/elasticsearch/reference/current/snippets/_executing_aggregations/4.json
還有不少其它的聚合功能在這裏咱們就不去詳細介紹了。若是你想了解更多,能夠參考聚合參考手冊。