Elasticsearch也是基於Lucene的全文檢索庫,本質也是存儲數據,不少概念與MySQL相似的。html
對比關係:mysql
索引(indices)--------------------------------Databases 數據庫sql
類型(type)-----------------------------Table 數據表數據庫
文檔(Document)----------------Row 行json
字段(Field)-------------------Columns 列數組
詳細說明:服務器
概念 | 說明 |
---|---|
索引庫(indices) | indices是index的複數,表明許多的索引, |
類型(type) | 類型是模擬mysql中的table概念,一個索引庫下能夠有不一樣類型的索引,好比商品索引,訂單索引,其數據格式不一樣。不過這會致使索引庫混亂,所以將來版本中會移除這個概念 |
文檔(document) | 存入索引庫原始的數據。好比每一條商品信息,就是一個文檔 |
字段(field) | 文檔中的屬性 |
映射配置(mappings) | 字段的數據類型、屬性、是否索引、是否存儲等特性 |
是否是與Lucene和solr中的概念相似。app
另外,在SolrCloud中,有一些集羣相關的概念,在Elasticsearch也有相似的:elasticsearch
要注意的是:Elasticsearch自己就是分佈式的,所以即使你只有一個節點,Elasticsearch默認也會對你的數據進行分片和副本操做,當你向集羣添加新數據時,數據也會在新加入的節點中進行平衡。分佈式
Elasticsearch採用Rest風格API,所以其API就是一次http請求,你能夠用任何工具發起http請求
建立索引的請求格式:
請求方式:PUT
請求路徑:/索引庫名
請求參數:json格式:
{ "settings": { "number_of_shards": 3, "number_of_replicas": 2 } }
咱們先用RestClient來試試
響應:
能夠看到索引建立成功了。
kibana的控制檯,能夠對http請求進行簡化,示例:
至關因而省去了elasticsearch的服務器地址
並且還有語法提示,很是舒服。
語法
Get請求能夠幫咱們查看索引信息,格式:
GET /索引庫名
或者,咱們可使用*來查詢全部索引庫配置:
刪除索引使用DELETE請求
語法
DELETE /索引庫名
示例
再次查看heima2:
固然,咱們也能夠用HEAD請求,查看索引是否存在:
索引有了,接下來確定是添加數據。可是,在添加數據以前必須定義映射。
什麼是映射?
映射是定義文檔的過程,文檔包含哪些字段,這些字段是否保存,是否索引,是否分詞等
只有配置清楚,Elasticsearch纔會幫咱們進行索引庫的建立(不必定)
語法
請求方式依然是PUT
PUT /索引庫名/_mapping/類型名稱 { "properties": { "字段名": { "type": "類型", "index": true, "store": true, "analyzer": "分詞器" } } }
ik_max_word
即便用ik分詞器示例
發起請求:
PUT heima/_mapping/goods { "properties": { "title": { "type": "text", "analyzer": "ik_max_word" }, "images": { "type": "keyword", "index": "false" }, "price": { "type": "float" } } }
響應結果:
{ "acknowledged": true }
語法:
GET /索引庫名/_mapping
示例:
GET /heima/_mapping
響應:
{ "heima": { "mappings": { "goods": { "properties": { "images": { "type": "keyword", "index": false }, "price": { "type": "float" }, "title": { "type": "text", "analyzer": "ik_max_word" } } } } } }
Elasticsearch中支持的數據類型很是豐富:
咱們說幾個關鍵的:
String類型,又分兩種:
Numerical:數值類型,分兩類
Date:日期類型
elasticsearch能夠對日期格式化爲字符串存儲,可是建議咱們存儲爲毫秒值,存儲爲long,節省空間。
index影響字段的索引狀況。
index的默認值就是true,也就是說你不進行任何配置,全部字段都會被索引。
可是有些字段是咱們不但願被索引的,好比商品的圖片信息,就須要手動設置index爲false。
是否將數據進行額外存儲。
在學習lucene和solr時,咱們知道若是一個字段的store設置爲false,那麼在文檔列表中就不會有這個字段的值,用戶的搜索結果中不會顯示出來。
可是在Elasticsearch中,即使store設置爲false,也能夠搜索到結果。
緣由是Elasticsearch在建立文檔索引時,會將文檔中的原始數據備份,保存到一個叫作_source
的屬性中。並且咱們能夠經過過濾_source
來選擇哪些要顯示,哪些不顯示。
而若是設置store爲true,就會在_source
之外額外存儲一份數據,多餘,所以通常咱們都會將store設置爲false,事實上,store的默認值就是false。
激勵因子,這個與lucene中同樣
其它的再也不一一講解,用的很少,你們參考官方文檔:
經過POST請求,能夠向一個已經存在的索引庫中添加數據。
語法:
POST /索引庫名/類型名 { "key":"value" }
示例:
POST /heima/goods/ { "title":"小米手機", "images":"http://image.leyou.com/12479122.jpg", "price":2699.00 }
響應:
{ "_index": "heima", "_type": "goods", "_id": "r9c1KGMBIhaxtY5rlRKv", "_version": 1, "result": "created", "_shards": { "total": 3, "successful": 1, "failed": 0 }, "_seq_no": 0, "_primary_term": 2 }
經過kibana查看數據:
get _search { "query":{ "match_all":{} } }
{ "_index": "heima", "_type": "goods", "_id": "r9c1KGMBIhaxtY5rlRKv", "_version": 1, "_score": 1, "_source": { "title": "小米手機", "images": "http://image.leyou.com/12479122.jpg", "price": 2699 } }
_source
:源文檔信息,全部的數據都在裏面。_id
:這條文檔的惟一標示,與文檔本身的id字段沒有關聯若是咱們想要本身新增的時候指定id,能夠這麼作:
POST /索引庫名/類型/id值 { ... }
示例:
POST /heima/goods/2 { "title":"大米手機", "images":"http://image.leyou.com/12479122.jpg", "price":2899.00 }
獲得的數據:
{ "_index": "heima", "_type": "goods", "_id": "2", "_score": 1, "_source": { "title": "大米手機", "images": "http://image.leyou.com/12479122.jpg", "price": 2899 } }
在學習Solr時咱們發現,咱們在新增數據時,只能使用提早配置好映射屬性的字段,不然就會報錯。
不過在Elasticsearch中並無這樣的規定。
事實上Elasticsearch很是智能,你不須要給索引庫設置任何mapping映射,它也能夠根據你輸入的數據來判斷類型,動態添加數據映射。
測試一下:
POST /heima/goods/3 { "title":"超米手機", "images":"http://image.leyou.com/12479122.jpg", "price":2899.00, "stock": 200, "saleable":true }
咱們額外添加了stock庫存,和saleable是否上架兩個字段。
來看結果:
{ "_index": "heima", "_type": "goods", "_id": "3", "_version": 1, "_score": 1, "_source": { "title": "超米手機", "images": "http://image.leyou.com/12479122.jpg", "price": 2899, "stock": 200, "saleable": true } }
在看下索引庫的映射關係:
{ "heima": { "mappings": { "goods": { "properties": { "images": { "type": "keyword", "index": false }, "price": { "type": "float" }, "saleable": { "type": "boolean" }, "stock": { "type": "long" }, "title": { "type": "text", "analyzer": "ik_max_word" } } } } } }
stock和saleable都被成功映射了。
若是存儲的是String類型數據,ES無智能判斷,他就會存入兩個字段。例如:
存入一個name字段,智能造成兩個字段:
把剛纔新增的請求方式改成PUT,就是修改了。不過修改必須指定id,
好比,咱們把id爲3的數據進行修改:
PUT /heima/goods/3 { "title":"超大米手機", "images":"http://image.leyou.com/12479122.jpg", "price":3899.00, "stock": 100, "saleable":true }
結果:
{ "took": 17, "timed_out": false, "_shards": { "total": 9, "successful": 9, "skipped": 0, "failed": 0 }, "hits": { "total": 1, "max_score": 1, "hits": [ { "_index": "heima", "_type": "goods", "_id": "3", "_score": 1, "_source": { "title": "超大米手機", "images": "http://image.leyou.com/12479122.jpg", "price": 3899, "stock": 100, "saleable": true } } ] } }
刪除使用DELETE請求,一樣,須要根據id進行刪除:
語法
DELETE /索引庫名/類型名/id值
示例:
咱們從4塊來說查詢:
_source
過濾基本語法
GET /索引庫名/_search { "query":{ "查詢類型":{ "查詢條件":"查詢條件值" } } }
這裏的query表明一個查詢對象,裏面能夠有不一樣的查詢屬性
match_all
, match
,term
, range
等等示例:
GET /heima/_search { "query":{ "match_all": {} } }
query
:表明查詢對象match_all
:表明查詢全部結果:
{ "took": 2, "timed_out": false, "_shards": { "total": 3, "successful": 3, "skipped": 0, "failed": 0 }, "hits": { "total": 2, "max_score": 1, "hits": [ { "_index": "heima", "_type": "goods", "_id": "2", "_score": 1, "_source": { "title": "大米手機", "images": "http://image.leyou.com/12479122.jpg", "price": 2899 } }, { "_index": "heima", "_type": "goods", "_id": "r9c1KGMBIhaxtY5rlRKv", "_score": 1, "_source": { "title": "小米手機", "images": "http://image.leyou.com/12479122.jpg", "price": 2699 } } ] } }
咱們先加入一條數據,便於測試:
PUT /heima/goods/3 { "title":"小米電視4A", "images":"http://image.leyou.com/12479122.jpg", "price":3899.00 }
如今,索引庫中有2部手機,1臺電視:
match
類型查詢,會把查詢條件進行分詞,而後進行查詢,多個詞條之間是or的關係
GET /heima/_search { "query":{ "match":{ "title":"小米電視" } } }
結果:
"hits": { "total": 2, "max_score": 0.6931472, "hits": [ { "_index": "heima", "_type": "goods", "_id": "tmUBomQB_mwm6wH_EC1-", "_score": 0.6931472, "_source": { "title": "小米手機", "images": "http://image.leyou.com/12479122.jpg", "price": 2699 } }, { "_index": "heima", "_type": "goods", "_id": "3", "_score": 0.5753642, "_source": { "title": "小米電視4A", "images": "http://image.leyou.com/12479122.jpg", "price": 3899 } } ] }
在上面的案例中,不只會查詢到電視,並且與小米相關的都會查詢到,多個詞之間是or
的關係。
某些狀況下,咱們須要更精確查找,咱們但願這個關係變成and
,能夠這樣作:
GET /heima/_search { "query":{ "match": { "title": { "query": "小米電視", "operator": "and" } } } }
結果:
{ "took": 2, "timed_out": false, "_shards": { "total": 3, "successful": 3, "skipped": 0, "failed": 0 }, "hits": { "total": 1, "max_score": 0.5753642, "hits": [ { "_index": "heima", "_type": "goods", "_id": "3", "_score": 0.5753642, "_source": { "title": "小米電視4A", "images": "http://image.leyou.com/12479122.jpg", "price": 3899 } } ] } }
本例中,只有同時包含小米
和電視
的詞條纔會被搜索到。
在 or
與 and
間二選一有點過於非黑即白。 若是用戶給定的條件分詞後有 5 個查詢詞項,想查找只包含其中 4 個詞的文檔,該如何處理?將 operator 操做符參數設置成 and
只會將此文檔排除。
有時候這正是咱們指望的,但在全文搜索的大多數應用場景下,咱們既想包含那些可能相關的文檔,同時又排除那些不太相關的。換句話說,咱們想要處於中間某種結果。
match
查詢支持 minimum_should_match
最小匹配參數, 這讓咱們能夠指定必須匹配的詞項數用來表示一個文檔是否相關。咱們能夠將其設置爲某個具體數字,更經常使用的作法是將其設置爲一個百分數
,由於咱們沒法控制用戶搜索時輸入的單詞數量:
GET /heima/_search { "query":{ "match":{ "title":{ "query":"小米曲面電視", "minimum_should_match": "75%" } } } }
本例中,搜索語句能夠分爲3個詞,若是使用and關係,須要同時知足3個詞纔會被搜索到。這裏咱們採用最小品牌數:75%,那麼也就是說只要匹配到總詞條數量的75%便可,這裏3*75% 約等於2。因此只要包含2個詞條就算知足條件了。
結果:
multi_match
與match
相似,不一樣的是它能夠在多個字段中查詢
GET /heima/_search { "query":{ "multi_match": { "query": "小米", "fields": [ "title", "subTitle" ] } } }
本例中,咱們會在title字段和subtitle字段中查詢小米
這個詞
term
查詢被用於精確值 匹配,這些精確值多是數字、時間、布爾或者那些未分詞的字符串
GET /heima/_search { "query":{ "term":{ "price":2699.00 } } }
結果:
{ "took": 2, "timed_out": false, "_shards": { "total": 3, "successful": 3, "skipped": 0, "failed": 0 }, "hits": { "total": 1, "max_score": 1, "hits": [ { "_index": "heima", "_type": "goods", "_id": "r9c1KGMBIhaxtY5rlRKv", "_score": 1, "_source": { "title": "小米手機", "images": "http://image.leyou.com/12479122.jpg", "price": 2699 } } ] } }
terms
查詢和 term 查詢同樣,但它容許你指定多值進行匹配。若是這個字段包含了指定值中的任何一個值,那麼這個文檔知足條件:
GET /heima/_search { "query":{ "terms":{ "price":[2699.00,2899.00,3899.00] } } }
結果:
{ "took": 4, "timed_out": false, "_shards": { "total": 3, "successful": 3, "skipped": 0, "failed": 0 }, "hits": { "total": 3, "max_score": 1, "hits": [ { "_index": "heima", "_type": "goods", "_id": "2", "_score": 1, "_source": { "title": "大米手機", "images": "http://image.leyou.com/12479122.jpg", "price": 2899 } }, { "_index": "heima", "_type": "goods", "_id": "r9c1KGMBIhaxtY5rlRKv", "_score": 1, "_source": { "title": "小米手機", "images": "http://image.leyou.com/12479122.jpg", "price": 2699 } }, { "_index": "heima", "_type": "goods", "_id": "3", "_score": 1, "_source": { "title": "小米電視4A", "images": "http://image.leyou.com/12479122.jpg", "price": 3899 } } ] } }
默認狀況下,elasticsearch在搜索的結果中,會把文檔中保存在_source
的全部字段都返回。
若是咱們只想獲取其中的部分字段,咱們能夠添加_source
的過濾
示例:
GET /heima/_search { "_source": ["title","price"], "query": { "term": { "price": 2699 } } }
返回的結果:
{ "took": 12, "timed_out": false, "_shards": { "total": 3, "successful": 3, "skipped": 0, "failed": 0 }, "hits": { "total": 1, "max_score": 1, "hits": [ { "_index": "heima", "_type": "goods", "_id": "r9c1KGMBIhaxtY5rlRKv", "_score": 1, "_source": { "price": 2699, "title": "小米手機" } } ] } }
咱們也能夠經過:
兩者都是可選的。
示例:
GET /heima/_search { "_source": { "includes":["title","price"] }, "query": { "term": { "price": 2699 } } }
與下面的結果將是同樣的:
GET /heima/_search { "_source": { "excludes": ["images"] }, "query": { "term": { "price": 2699 } } }
bool
把各類其它查詢經過must
(與)、must_not
(非)、should
(或)的方式進行組合
GET /heima/_search { "query":{ "bool":{ "must": { "match": { "title": "大米" }}, "must_not": { "match": { "title": "電視" }}, "should": { "match": { "title": "手機" }} } } }
結果:
{ "took": 10, "timed_out": false, "_shards": { "total": 3, "successful": 3, "skipped": 0, "failed": 0 }, "hits": { "total": 1, "max_score": 0.5753642, "hits": [ { "_index": "heima", "_type": "goods", "_id": "2", "_score": 0.5753642, "_source": { "title": "大米手機", "images": "http://image.leyou.com/12479122.jpg", "price": 2899 } } ] } }
range
查詢找出那些落在指定區間內的數字或者時間
GET /heima/_search { "query":{ "range": { "price": { "gte": 1000.0, "lt": 2800.00 } } } }
range
查詢容許如下字符:
操做符 | 說明 |
---|---|
gt | 大於 |
gte | 大於等於 |
lt | 小於 |
lte | 小於等於 |
咱們新增一個商品:
POST /heima/goods/4 { "title":"apple手機", "images":"http://image.leyou.com/12479122.jpg", "price":6899.00 }
fuzzy
查詢是 term
查詢的模糊等價。它容許用戶搜索詞條與實際詞條的拼寫出現誤差,可是誤差的編輯距離不得超過2:
GET /heima/_search { "query": { "fuzzy": { "title": "appla" } } }
上面的查詢,也能查詢到apple手機
咱們能夠經過fuzziness
來指定容許的編輯距離:
GET /heima/_search { "query": { "fuzzy": { "title": { "value":"appla", "fuzziness":1 } } } }
條件查詢中進行過濾
全部的查詢都會影響到文檔的評分及排名。若是咱們須要在查詢結果中進行過濾,而且不但願過濾條件影響評分,那麼就不要把過濾條件做爲查詢條件來用。而是使用filter
方式:
GET /heima/_search { "query":{ "bool":{ "must":{ "match": { "title": "小米手機" }}, "filter":{ "range":{"price":{"gt":2000.00,"lt":3800.00}} } } } }
注意:filter
中還能夠再次進行bool
組合條件過濾。
無查詢條件,直接過濾
若是一次查詢只有過濾,沒有查詢條件,不但願進行評分,咱們可使用constant_score
取代只有 filter 語句的 bool 查詢。在性能上是徹底相同的,但對於提升查詢簡潔性和清晰度有很大幫助。
GET /heima/_search { "query":{ "constant_score": { "filter": { "range":{"price":{"gt":2000.00,"lt":3000.00}} } } }
sort
可讓咱們按照不一樣的字段進行排序,而且經過order
指定排序的方式
GET /heima/_search { "query": { "match": { "title": "小米手機" } }, "sort": [ { "price": { "order": "desc" } } ] }
假定咱們想要結合使用 price和 _score(得分) 進行查詢,而且匹配的結果首先按照價格排序,而後按照相關性得分排序:
GET /goods/_search { "query":{ "bool":{ "must":{ "match": { "title": "小米手機" }}, "filter":{ "range":{"price":{"gt":200000,"lt":300000}} } } }, "sort": [ { "price": { "order": "desc" }}, { "_score": { "order": "desc" }} ] }
聚合可讓咱們極其方便的實現對數據的統計、分析。例如:
實現這些統計功能的比數據庫的sql要方便的多,並且查詢速度很是快,能夠實現實時搜索效果。
Elasticsearch中的聚合,包含多種類型,最經常使用的兩種,一個叫桶
,一個叫度量
:
桶(bucket)
桶的做用,是按照某種方式對數據進行分組,每一組數據在ES中稱爲一個桶
,例如咱們根據國籍對人劃分,能夠獲得中國桶
、英國桶
,日本桶
……或者咱們按照年齡段對人進行劃分:0~10,10~20,20~30,30~40等。
Elasticsearch中提供的劃分桶的方式有不少:
綜上所述,咱們發現bucket aggregations 只負責對數據進行分組,並不進行計算,所以每每bucket中每每會嵌套另外一種聚合:metrics aggregations即度量
度量(metrics)
分組完成之後,咱們通常會對組中的數據進行聚合運算,例如求平均值、最大、最小、求和等,這些在ES中稱爲度量
比較經常使用的一些度量聚合方式:
爲了測試聚合,咱們先批量導入一些數據
建立索引:
PUT /cars { "settings": { "number_of_shards": 1, "number_of_replicas": 0 }, "mappings": { "transactions": { "properties": { "color": { "type": "keyword" }, "make": { "type": "keyword" } } } } }
注意:在ES中,須要進行聚合、排序、過濾的字段其處理方式比較特殊,所以不能被分詞。這裏咱們將color和make這兩個文字類型的字段設置爲keyword類型,這個類型不會被分詞,未來就能夠參與聚合
導入數據
POST /cars/transactions/_bulk { "index": {}} { "price" : 10000, "color" : "red", "make" : "honda", "sold" : "2014-10-28" } { "index": {}} { "price" : 20000, "color" : "red", "make" : "honda", "sold" : "2014-11-05" } { "index": {}} { "price" : 30000, "color" : "green", "make" : "ford", "sold" : "2014-05-18" } { "index": {}} { "price" : 15000, "color" : "blue", "make" : "toyota", "sold" : "2014-07-02" } { "index": {}} { "price" : 12000, "color" : "green", "make" : "toyota", "sold" : "2014-08-19" } { "index": {}} { "price" : 20000, "color" : "red", "make" : "honda", "sold" : "2014-11-05" } { "index": {}} { "price" : 80000, "color" : "red", "make" : "bmw", "sold" : "2014-01-01" } { "index": {}} { "price" : 25000, "color" : "blue", "make" : "ford", "sold" : "2014-02-12" }
首先,咱們按照 汽車的顏色color
來劃分桶
GET /cars/_search { "size" : 0, "aggs" : { "popular_colors" : { "terms" : { "field" : "color" } } } }
結果:
{ "took": 1, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": 8, "max_score": 0, "hits": [] }, "aggregations": { "popular_colors": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ { "key": "red", "doc_count": 4 }, { "key": "blue", "doc_count": 2 }, { "key": "green", "doc_count": 2 } ] } } }
經過聚合的結果咱們發現,目前紅色的小車比較暢銷!
前面的例子告訴咱們每一個桶裏面的文檔數量,這頗有用。 但一般,咱們的應用須要提供更復雜的文檔度量。 例如,每種顏色汽車的平均價格是多少?
所以,咱們須要告訴Elasticsearch使用哪一個字段
,使用何種度量方式
進行運算,這些信息要嵌套在桶
內,度量
的運算會基於桶
內的文檔進行
如今,咱們爲剛剛的聚合結果添加 求價格平均值的度量:
GET /cars/_search { "size" : 0, "aggs" : { "popular_colors" : { "terms" : { "field" : "color" }, "aggs":{ "avg_price": { "avg": { "field": "price" } } } } } }
度量
也是一個聚合,度量是在桶內的聚合結果:
... "aggregations": { "popular_colors": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ { "key": "red", "doc_count": 4, "avg_price": { "value": 32500 } }, { "key": "blue", "doc_count": 2, "avg_price": { "value": 20000 } }, { "key": "green", "doc_count": 2, "avg_price": { "value": 21000 } } ] } } ...
能夠看到每一個桶中都有本身的avg_price
字段,這是度量聚合的結果
剛剛的案例中,咱們在桶內嵌套度量運算。事實上桶不只能夠嵌套運算, 還能夠再嵌套其它桶。也就是說在每一個分組中,再分更多組。
好比:咱們想統計每種顏色的汽車中,分別屬於哪一個製造商,按照make
字段再進行分桶
GET /cars/_search { "size" : 0, "aggs" : { "popular_colors" : { "terms" : { "field" : "color" }, "aggs":{ "avg_price": { "avg": { "field": "price" } }, "maker":{ "terms":{ "field":"make" } } } } } }
部分結果:
... {"aggregations": { "popular_colors": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ { "key": "red", "doc_count": 4, "maker": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ { "key": "honda", "doc_count": 3 }, { "key": "bmw", "doc_count": 1 } ] }, "avg_price": { "value": 32500 } }, { "key": "blue", "doc_count": 2, "maker": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ { "key": "ford", "doc_count": 1 }, { "key": "toyota", "doc_count": 1 } ] }, "avg_price": { "value": 20000 } }, { "key": "green", "doc_count": 2, "maker": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ { "key": "ford", "doc_count": 1 }, { "key": "toyota", "doc_count": 1 } ] }, "avg_price": { "value": 21000 } } ] } } } ...
maker
被嵌套在原來每個color
的桶中。make
字段進行了分組前面講了,劃分桶的方式有不少,例如:
剛剛的案例中,咱們採用的是Terms Aggregation,即根據詞條劃分桶。
接下來,咱們再學習幾個比較實用的:
原理:
histogram是把數值類型的字段,按照必定的階梯大小進行分組。你須要指定一個階梯值(interval)來劃分階梯大小。
舉例:
好比你有價格字段,若是你設定interval的值爲200,那麼階梯就會是這樣的:
0,200,400,600,...
上面列出的是每一個階梯的key,也是區間的啓點。
若是一件商品的價格是450,會落入哪一個階梯區間呢?計算公式以下:
bucket_key = Math.floor((value - offset) / interval) * interval + offset
value:就是當前數據的值,本例中是450
offset:起始偏移量,默認爲0
interval:階梯間隔,好比200
所以你獲得的key = Math.floor((450 - 0) / 200) * 200 + 0 = 400
操做一下:
好比,咱們對汽車的價格進行分組,指定間隔interval爲5000:
GET /cars/_search { "size":0, "aggs":{ "price":{ "histogram": { "field": "price", "interval": 5000 } } } }
結果:
{ "took": 21, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 8, "max_score": 0, "hits": [] }, "aggregations": { "price": { "buckets": [ { "key": 10000, "doc_count": 2 }, { "key": 15000, "doc_count": 1 }, { "key": 20000, "doc_count": 2 }, { "key": 25000, "doc_count": 1 }, { "key": 30000, "doc_count": 1 }, { "key": 35000, "doc_count": 0 }, { "key": 40000, "doc_count": 0 }, { "key": 45000, "doc_count": 0 }, { "key": 50000, "doc_count": 0 }, { "key": 55000, "doc_count": 0 }, { "key": 60000, "doc_count": 0 }, { "key": 65000, "doc_count": 0 }, { "key": 70000, "doc_count": 0 }, { "key": 75000, "doc_count": 0 }, { "key": 80000, "doc_count": 1 } ] } } }
你會發現,中間有大量的文檔數量爲0 的桶,看起來很醜。
咱們能夠增長一個參數min_doc_count爲1,來約束最少文檔數量爲1,這樣文檔數量爲0的桶會被過濾
示例:
GET /cars/_search { "size":0, "aggs":{ "price":{ "histogram": { "field": "price", "interval": 5000, "min_doc_count": 1 } } } }
結果:
{ "took": 15, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 8, "max_score": 0, "hits": [] }, "aggregations": { "price": { "buckets": [ { "key": 10000, "doc_count": 2 }, { "key": 15000, "doc_count": 1 }, { "key": 20000, "doc_count": 2 }, { "key": 25000, "doc_count": 1 }, { "key": 30000, "doc_count": 1 }, { "key": 80000, "doc_count": 1 } ] } } }
完美,!
若是你用kibana將結果變爲柱形圖,會更好看:
範圍分桶與階梯分桶相似,也是把數字按照階段進行分組,只不過range方式須要你本身指定每一組的起始和結束大小。
原文出處:https://www.cnblogs.com/jimlau/p/12143251.html