目錄
索引庫操作
1.mapping映射屬性
2.建立索引庫和映射
3.查詢索引庫
4.修改索引庫
5.删除索引庫
文檔操作
1.新增文檔
2.查詢文檔
3.删除文檔
4.修改文檔
全量修改
增量修改
DSL 查詢文檔
1.查詢所有
編輯
2.全文檢索查詢
單字段查詢
多字段查詢
3.精準查詢
term查詢
rang查詢
4.地理坐标查詢
矩形範圍查詢
附近查詢
5.複合查詢
相關性算分
6.算分函數查詢
7.布爾查詢(多條件查詢)
8.排序
普通字段排序
地理坐标排序
9.分頁
分頁深度問題
分頁小結:
10.搜尋結果 -- 高亮
11.資料聚合
Bucket聚合
聚合結果排序
限定聚合範圍
Metric聚合文法
12.自動補全查詢
索引庫操作
索引庫就類似資料庫表,mapping映射就類似表的結構。
我們要向es中存儲資料,必須先建立“庫”和“表”。
1.mapping映射屬性
mapping是對索引庫中文檔的限制,常見的mapping屬性包括:
- type:字段資料類型,常見的簡單類型有:
- 字元串:text(可分詞的文本)、keyword(精确值,例如:品牌、國家、ip位址)
- 數值:long、integer、short、byte、double、float、
- 布爾:boolean
- 日期:date
- 對象:object
- index:是否建立反向索引,預設為true
- analyzer:使用哪種分詞器
- properties:該字段的子字段
例如下面的json文檔:
{
"age": 21,
"weight": 52.1,
"isMarried": false,
"info": "四大美人之一貂蟬",
"email": "[email protected]",
"score": [99.1, 99.5, 98.9],
"name": {
"firstName": "貂",
"lastName": "蟬"
}
}
對應的每個字段映射(mapping):
- age:類型為 integer;參與搜尋,是以需要index為true;無需分詞器
- weight:類型為float;參與搜尋,是以需要index為true;無需分詞器
- isMarried:類型為boolean;參與搜尋,是以需要index為true;無需分詞器
- info:類型為字元串,需要分詞,是以是text;參與搜尋,是以需要index為true;需要分詞器
- email:類型為字元串,但是不需要分詞,是以是keyword;不參與搜尋,是以需要index為false;無需分詞器
- score:雖然是數組,但是我們隻看元素的類型,類型為float;參與搜尋,是以需要index為true;無需分詞器(es 沒有數組類型,一個字段可以有多個值)
- name:類型為object,需要定義多個子屬性
- name.firstName;類型為字元串,但是不需要分詞,是以是keyword;參與搜尋,是以需要index為true;無需分詞器
- name.lastName;類型為字元串,但是不需要分詞,是以是keyword;參與搜尋,是以需要index為true;無需分詞器
2.建立索引庫和映射
基本文法:
- 請求方式:PUT
- 請求路徑:/索引庫名,可以自定義
- 請求參數:mapping映射
PUT /索引庫名稱
{
"mappings": {
"properties": {
"字段名":{
"type": "text",
"analyzer": "ik_smart"
},
"字段名2":{
"type": "keyword",
"index": "false"
},
"字段名3":{
"properties": {
"子字段": {
"type": "keyword"
}
}
}
}
}
}
示例:
#建立索引庫
PUT /lb
{
"mappings": {
"properties": {
"info": {
"type": "text",
"analyzer": "ik_smart"
},
"email": {
"type": "keyword",
"index": false
},
"name": {
"properties": {
"firstName": {
"type": "keyword"
},
"lastName": {
"type": "keyword"
}
}
}
}
}
}
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnL2kTOzEWNyYDMkJ2M1YmZ4UzN0QTZ3UTNlZ2NhFjZiFzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
3.查詢索引庫
基本文法:
- 請求方式:GET
- 請求路徑:/索引庫名
- 請求參數:無
GET /索引庫名
4.修改索引庫
反向索引結構雖然不複雜,但是一旦資料結構改變(比如改變了分詞器),就需要重新建立反向索引,這簡直是災難。是以索引庫一旦建立,無法修改mapping。
雖然無法修改mapping中已有的字段,但是卻允許添加新的字段到mapping中,因為不會對反向索引産生影響。
PUT /索引庫名/_mapping
{
"properties": {
"新字段名":{
"type": "integer"
}
}
}
5.删除索引庫
DELETE /索引庫名
文檔操作
1.新增文檔
POST /索引庫名/_doc/文檔id
{
"字段1": "值1",
"字段2": "值2",
"字段3": {
"子屬性1": "值3",
"子屬性2": "值4"
},
// ...
}
示例
POST /heima/_doc/1
{
"info": "黑馬程式員Java講師",
"email": "[email protected]",
"name": {
"firstName": "雲",
"lastName": "趙"
}
}
2.查詢文檔
根據rest風格,新增是post,查詢應該是get,不過查詢一般都需要條件,這裡我們把文檔id帶上。
GET /{索引庫名稱}/_doc/{id}
通過kibana檢視資料:
GET /heima/_doc/1
3.删除文檔
删除使用DELETE請求,同樣,需要根據id進行删除:
DELETE /{索引庫名}/_doc/id值
# 根據id删除資料
DELETE /heima/_doc/1
4.修改文檔
修改有兩種方式:
- 全量修改:直接覆寫原來的文檔
- 增量修改:修改文檔中的部分字段
全量修改
全量修改是覆寫原來的文檔,其本質是:
- 根據指定的id删除文檔
- 新增一個相同id的文檔
注意:如果根據id删除時,id不存在,第二步的新增也會執行,也就從修改變成了新增操作了。
PUT /{索引庫名}/_doc/文檔id
{
"字段1": "值1",
"字段2": "值2",
// ... 略
}
PUT /heima/_doc/1
{
"info": "黑馬程式員進階Java講師",
"email": "[email protected]",
"name": {
"firstName": "雲",
"lastName": "趙"
}
}
增量修改
增量修改是隻修改指定id比對的文檔中的部分字段。
POST /{索引庫名}/_update/文檔id
{
"doc": {
"字段名": "新的值",
}
}
POST /heima/_update/1
{
"doc": {
"email": "[email protected]"
}
}
DSL 查詢文檔
1.查詢所有
// 查詢所有
GET /indexName/_search
{
"query": {
"match_all": {}
}
}
elasticsearch DSL指令索引庫操作 文檔操作DSL 查詢文檔
2.全文檢索查詢
全文檢索查詢的基本流程如下:
- 對使用者搜尋的内容做分詞,得到詞條
- 根據詞條去反向索引庫中比對,得到文檔id
- 根據文檔id找到文檔,傳回給使用者
比較常用的場景包括:
- 商城的輸入框搜尋
- 百度輸入框搜尋
因為是拿着詞條去比對,是以參與搜尋的字段也必須是可分詞的text類型的字段
單字段查詢
- match查詢:單字段查詢
GET /indexName/_search
{
"query": {
"match": {
"FIELD": "TEXT"
}
}
}
“all”是可分詞字段
多字段查詢
- multi_match查詢:多字段查詢,任意一個字段符合條件就算符合查詢條件
match查詢文法如下
GET /indexName/_search
{
"query": {
"multi_match": {
"query": "TEXT",
"fields": ["FIELD1", " FIELD12"]
}
}
}
多字段查詢和利用把這幾個多字段copy_to到all字段,查詢結果一樣,但是,搜尋字段越多,對查詢性能影響越大,是以建議采用copy_to,然後單字段查詢的方式。
3.精準查詢
精确查詢一般是查找keyword、數值、日期、boolean等類型字段。是以不會對搜尋條件分詞。常見的有:
- term:根據詞條精确值查詢
- range:根據值的範圍查詢
term查詢
- term查詢:根據詞條精确比對,一般搜尋keyword類型、數值類型、布爾類型、日期類型字段
1.查詢分詞字段,則查詢到包含該查詢條件的文檔
2.查詢精準字段,則字段内容必須和查詢條件完全一緻,否則插叙不到
// term查詢
GET /indexName/_search
{
"query": {
"term": {
"FIELD": {
"value": "VALUE"
}
}
}
}
rang查詢
- range查詢:根據數值範圍查詢,可以是數值、日期的範圍
範圍查詢,一般應用在對數值類型做範圍過濾的時候。比如做價格範圍過濾。
// range查詢
GET /indexName/_search
{
"query": {
"range": {
"FIELD": {
"gte": 10, // 這裡的gte代表大于等于,gt則代表大于
"lte": 20 // lte代表小于等于,lt則代表小于
}
}
}
}
4.地理坐标查詢
所謂的地理坐标查詢,其實就是根據經緯度查詢,官方文檔:Geo queries | Elasticsearch Guide [8.4] | Elastic
常見的使用場景包括:
- 攜程:搜尋我附近的酒店
- 滴滴:搜尋我附近的計程車
- 微信:搜尋我附近的人
矩形範圍查詢
矩形範圍查詢,也就是geo_bounding_box查詢,查詢坐标落在某個矩形範圍的所有文檔:
查詢時,需要指定矩形的左上、右下兩個點的坐标,然後畫出一個矩形,落在該矩形内的都是符合條件的點。
文法如下:
// geo_bounding_box查詢
GET /indexName/_search
{
"query": {
"geo_bounding_box": {
"FIELD": {
"top_left": { // 左上點
"lat": 31.1,
"lon": 121.5
},
"bottom_right": { // 右下點
"lat": 30.9,
"lon": 121.7
}
}
}
}
}
附近查詢
附近查詢,也叫做距離查詢(geo_distance):查詢到指定中心點小于某個距離值的所有文檔。
換句話來說,在地圖上找一個點作為圓心,以指定距離為半徑,畫一個圓,落在圓内的坐标都算符合條件:
// geo_distance 查詢
GET /indexName/_search
{
"query": {
"geo_distance": {
"distance": "15km", // 半徑
"FIELD": "31.21,121.5" // 圓心
}
}
}
查詢15km内的酒店
發現47家酒店,縮小範圍
5.複合查詢
複合(compound)查詢:複合查詢可以将其它簡單查詢組合起來,實作更複雜的搜尋邏輯。常見的有兩種:
- fuction score:算分函數查詢,可以控制文檔相關性算分,控制文檔排名
- bool query:布爾查詢,利用邏輯關系組合多個其它的查詢,實作複雜搜尋
相關性算分
當我們利用match查詢時,文檔結果會根據與搜尋詞條的關聯度打分(_score),傳回結果時按照分值降序排列。
例如,我們搜尋 "虹橋如家",結果如下:
[
{
"_score" : 17.850193,
"_source" : {
"name" : "虹橋如家酒店真不錯",
}
},
{
"_score" : 12.259849,
"_source" : {
"name" : "外灘如家酒店真不錯",
}
},
{
"_score" : 11.91091,
"_source" : {
"name" : "迪士尼如家酒店真不錯",
}
}
]
在elasticsearch中,早期使用的打分算法是TF-IDF算法,公式如下:
在後來的5.1版本更新中,elasticsearch将算法改進為BM25算法,公式如下:
TF-IDF算法有一各缺陷,就是詞條頻率越高,文檔得分也會越高,單個詞條對文檔影響較大。而BM25則會讓單個詞條的算分有一個上限,曲線更加平滑:
6.算分函數查詢
根據相關度打分是比較合理的需求,但合理的不一定是産品經理需要的。
以XX為例,你搜尋的結果中,并不是相關度越高排名越靠前,而是誰掏的錢多排名就越靠前.
要想認為控制相關性算分,就需要利用elasticsearch中的function score 查詢了。
文法說明
function score 查詢中包含四部分内容:
- 原始查詢條件:query部分,基于這個條件搜尋文檔,并且基于BM25算法給文檔打分,原始算分(query score)
- 過濾條件:filter部分,符合該條件的文檔才會重新算分
- 算分函數:符合filter條件的文檔要根據這個函數做運算,得到的函數算分(function score),有四種函數
- weight:函數結果是常量
- field_value_factor:以文檔中的某個字段值作為函數結果
- random_score:以随機數作為函數結果
- script_score:自定義算分函數算法
- 運算模式:算分函數的結果、原始查詢的相關性算分,兩者之間的運算方式,包括:
- multiply:相乘
- replace:用function score替換query score
- 其它,例如:sum、avg、max、min
function score的運作流程如下:
- 1)根據原始條件查詢搜尋文檔,并且計算相關性算分,稱為原始算分(query score)
- 2)根據過濾條件,過濾文檔
- 3)符合過濾條件的文檔,基于算分函數運算,得到函數算分(function score)
- 4)将原始算分(query score)和函數算分(function score)基于運算模式做運算,得到最終結果,作為相關性算分。
是以,其中的關鍵點是:
- 過濾條件:決定哪些文檔的算分被修改
- 算分函數:決定函數算分的算法
- 運算模式:決定最終算分結果
需求:給“如家”這個品牌的酒店排名靠前一些
翻譯一下這個需求,轉換為之前說的四個要點:
是以最終的DSL語句如下:
- 原始條件:不确定,可以任意變化
- 過濾條件:brand = "如家"
- 算分函數:可以簡單粗暴,直接給固定的算分結果,weight
- 運算模式:比如求和
測試,在未添加算分函數時,如家得分如下:GET /hotel/_search { "query": { "function_score": { "query": { .... }, // 原始查詢,可以是任意條件 "functions": [ // 算分函數 { "filter": { // 滿足的條件,品牌必須是如家 "term": { "brand": "如家" } }, "weight": 2 // 算分權重為2 } ], "boost_mode": "sum" // 權重模式,求和 } } }
添加了算分函數後,如家得分就提升了:![]()
elasticsearch DSL指令索引庫操作 文檔操作DSL 查詢文檔 ![]()
elasticsearch DSL指令索引庫操作 文檔操作DSL 查詢文檔
7.布爾查詢(多條件查詢)
布爾查詢是一個或多個查詢子句的組合,每一個子句就是一個子查詢。子查詢的組合方式有:
- must:必須比對每個子查詢,類似“與”
- should:選擇性比對子查詢,類似“或”
- must_not:必須不比對,不參與算分,類似“非”
- filter:必須比對,不參與算分
比如在搜尋酒店時,除了關鍵字搜尋外,我們還可能根據品牌、價格、城市等字段做過濾:
每一個不同的字段,其查詢的條件、方式都不一樣,必須是多個不同的查詢,而要組合這些查詢,就必須用bool查詢了。
需要注意的是,搜尋時,參與打分的字段越多,查詢的性能也越差。是以這種多條件查詢時,建議這樣做:
- 搜尋框的關鍵字搜尋,是全文檢索查詢,使用must查詢,參與算分
- 其它過濾條件,采用filter查詢。不參與算分
1)文法示例:
GET /hotel/_search
{
"query": {
"bool": {
"must": [
{"term": {"city": "上海" }}
],
"should": [
{"term": {"brand": "皇冠假日" }},
{"term": {"brand": "華美達" }}
],
"must_not": [
{ "range": { "price": { "lte": 500 } }}
],
"filter": [
{ "range": {"score": { "gte": 45 } }}
]
}
}
}
2)示例
需求:搜尋名字包含“如家”,價格不高于400,在坐标31.21,121.5周圍10km範圍内的酒店。
分析:
- 名稱搜尋,屬于全文檢索查詢,應該參與算分。放到must中
- 價格不高于400,用range查詢,屬于過濾條件,不參與算分。放到must_not中
- 周圍10km範圍内,用geo_distance查詢,屬于過濾條件,不參與算分。放到filter中
![]()
elasticsearch DSL指令索引庫操作 文檔操作DSL 查詢文檔 GET /hotel/_search { "query": { "bool": { "must": [{ "match": { "name": "如家" } }], "must_not": [{ "range": { "price": { "gt": 400 } } }], "filter": [{ "geo_distance": { "distance": "10km", "location": { "lat": 31.21, "lon": 121.5 } } }] } } }
8.排序
搜尋的結果可以按照使用者指定的方式去處理或展示。
elasticsearch預設是根據相關度算分(_score)來排序,但是也支援自定義方式對搜尋結果排序。可以排序字段類型有:keyword類型、數值類型、地理坐标類型、日期類型等。
普通字段排序
keyword、數值、日期類型排序的文法基本一緻。
文法:
GET /indexName/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"FIELD": "desc" // 排序字段、排序方式ASC、DESC
}
]
}
排序條件是一個數組,也就是可以寫多個排序條件。按照聲明的順序,當第一個條件相等時,再按照第二個條件排序,以此類推
示例:酒店資料按照使用者評價(score)降序排序,評價相同的按照價格(price)升序排序GET /hotel/_search { "query": { "match_all": {} }, "sort": [ { "score": "desc" }, { "price": "asc" } ] }
地理坐标排序
地理坐标排序略有不同。
文法說明:
GET /indexName/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"_geo_distance" : {
"FIELD" : "緯度,經度", // 文檔中geo_point類型的字段名、目标坐标點
"order" : "asc", // 排序方式
"unit" : "km" // 排序的距離機關
}
}
]
這個查詢的含義是:
- 指定一個坐标,作為目标點
- 計算每一個文檔中,指定字段(必須是geo_point類型)的坐标 到目标點的距離是多少
- 根據距離排序
示例: 實作對酒店資料按照到你的位置坐标的距離升序排序
提示:擷取你的位置的經緯度的方式:擷取滑鼠點選經緯度-地圖屬性-示例中心-JS API 2.0 示例 | 高德地圖API
假設我的位置是:31.034661,121.612282,尋找我周圍距離最近的酒店。
經緯度 2 種書寫方式都可以GET /hotel/_search { "query": { "match_all": {} }, "sort": [ { "_geo_distance": { "location": { "lat": 31.034661, "lon": 121.612282 }, "order": "asc", "unit": "km" } } ] }
![]()
elasticsearch DSL指令索引庫操作 文檔操作DSL 查詢文檔
9.分頁
elasticsearch 預設情況下隻傳回top10的資料。而如果要查詢更多資料就需要修改分頁參數了。elasticsearch中通過修改from、size參數來控制要傳回的分頁結果:
- from:從第幾個文檔開始
- size:總共查詢幾個文檔
類似于mysql中的
limit ?, ?
基本文法如下:
GET /hotel/_search
{
"query": {
"match_all": {}
},
"from": 0, // 分頁開始的位置,預設為0
"size": 10, // 期望擷取的文檔總數
"sort": [
{"price": "asc"}
]
}
分頁深度問題
現在,我要查詢990~1000的資料,查詢邏輯要這麼寫:
GET /hotel/_search
{
"query": {
"match_all": {}
},
"from": 990, // 分頁開始的位置,預設為0
"size": 10, // 期望擷取的文檔總數
"sort": [
{"price": "asc"}
]
}
這裡是查詢990開始的資料,也就是 第990~第1000條 資料。
不過,elasticsearch内部分頁時,必須先查詢 0~1000條,然後截取其中的990 ~ 1000的這10條:
查詢TOP1000,如果es是單點模式,這并無太大影響。
但是elasticsearch将來一定是叢集,例如我叢集有5個節點,我要查詢TOP1000的資料,并不是每個節點查詢200條就可以了。
因為節點A的TOP200,在另一個節點可能排到10000名以外了。
是以要想擷取整個叢集的TOP1000,必須先查詢出每個節點的TOP1000,彙總結果後,重新排名,重新截取TOP1000。
那如果我要查詢9900~10000的資料呢?是不是要先查詢TOP10000呢?那每個節點都要查詢10000條?彙總到記憶體中?
當查詢分頁深度較大時,彙總資料過多,對記憶體和CPU會産生非常大的壓力,是以elasticsearch會禁止from+ size 超過10000的請求。
針對深度分頁,ES提供了兩種解決方案,官方文檔:
- search after:分頁時需要排序,原理是從上一次的排序值開始,查詢下一頁資料。官方推薦使用的方式。
- scroll:原理将排序後的文檔id形成快照,儲存在記憶體。官方已經不推薦使用。
分頁小結:
分頁查詢的常見實作方案以及優缺點:
-
:from + size
- 優點:支援随機翻頁
- 缺點:深度分頁問題,預設查詢上限(from + size)是10000
- 場景:百度、京東、谷歌、淘寶這樣的随機翻頁搜尋
-
:after search
- 優點:沒有查詢上限(單次查詢的size不超過10000)
- 缺點:隻能向後逐頁查詢,不支援随機翻頁
- 場景:沒有随機翻頁需求的搜尋,例如手機向下滾動翻頁
-
:scroll
- 優點:沒有查詢上限(單次查詢的size不超過10000)
- 缺點:會有額外記憶體消耗,并且搜尋結果是非實時的
- 場景:海量資料的擷取和遷移。從ES7.1開始不推薦,建議用 after search方案。
10.搜尋結果 -- 高亮
什麼是高亮顯示呢?
我們在百度,京東搜尋時,關鍵字會變成紅色,比較醒目,這叫高亮顯示:
高亮顯示的實作分為兩步:
- 1)給文檔中的所有關鍵字都添加一個标簽,例如
标簽<em>
- 2)頁面給
标簽編寫CSS樣式<em>
高亮的文法:
GET /hotel/_search
{
"query": {
"match": {
"FIELD": "TEXT" // 查詢條件,高亮一定要使用全文檢索查詢
}
},
"highlight": {
"fields": { // 指定要高亮的字段
"FIELD": {
"pre_tags": "<em>", // 用來标記高亮字段的前置标簽
"post_tags": "</em>" // 用來标記高亮字段的後置标簽
}
}
}
}
注意:
- 高亮是對關鍵字高亮,是以搜尋條件必須帶有關鍵字,而不能是範圍這樣的查詢。
- 預設情況下,高亮的字段,必須與搜尋指定的字段一緻,否則無法高亮
- 如果要對非搜尋字段高亮,則需要添加一個屬性:required_field_match=false
GET /hotel/_search { "query": { "match": { "all": "外灘" } }, "highlight": { "fields": { "name": { "require_field_match": "false" } } } }
![]()
elasticsearch DSL指令索引庫操作 文檔操作DSL 查詢文檔
11.資料聚合
聚合(aggregations)可以讓我們極其友善的實作對資料的統計、分析、運算。例如:
- 什麼品牌的手機最受歡迎?
- 這些手機的平均價格、最高價格、最低價格?
- 這些手機每月的銷售情況如何?
實作這些統計功能的比資料庫的sql要友善的多,而且查詢速度非常快,可以實作近實時搜尋效果。
聚合的種類:
聚合常見的有三類:
- 桶(Bucket)聚合:用來對文檔做分組
- TermAggregation:按照文檔字段值分組,例如按照品牌值分組、按照國家分組
- Date Histogram:按照日期階梯分組,例如一周為一組,或者一月為一組
- 度量(Metric)聚合:用以計算一些值,比如:最大值、最小值、平均值等
- Avg:求平均值
- Max:求最大值
- Min:求最小值
- Stats:同時求max、min、avg、sum等
- 管道(pipeline)聚合:其它聚合的結果為基礎做聚合
注意:參加聚合的字段必須是keyword、日期、數值、布爾類型
Bucket聚合
GET /hotel/_search
{
"size": 0, // 設定size為0,結果中不包含文檔,隻包含聚合結果
"aggs": { // 定義聚合
"brandAgg": { //給聚合起個名字
"terms": { // 聚合的類型,按照品牌值聚合,是以選擇term
"field": "brand", // 參與聚合的字段
"size": 20 // 希望擷取的聚合結果數量
}
}
}
}
結果如圖:
聚合結果排序
預設情況下,Bucket聚合會統計Bucket内的文檔數量,記為count,并且按照count降序排序。
我們可以指定order屬性,自定義聚合的排序方式:
GET /hotel/_search
{
"size": 0,
"aggs": {
"brandAgg": {
"terms": {
"field": "brand",
"order": {
"_count": "asc" // 按照_count升序排列
},
"size": 20
}
}
}
}
限定聚合範圍
預設情況下,Bucket聚合是對索引庫的所有文檔做聚合,但真實場景下,使用者會輸入搜尋條件,是以聚合必須是對搜尋結果聚合。那麼聚合必須添加限定條件。
我們可以限定要聚合的文檔範圍,隻要添加query條件即可:
GET /hotel/_search
{
"query": {
"range": {
"price": {
"lte": 200 // 隻對200元以下的文檔聚合
}
}
},
"size": 0,
"aggs": {
"brandAgg": {
"terms": {
"field": "brand",
"size": 20
}
}
}
}
Metric聚合文法
我們對酒店按照品牌分組,形成了一個個桶。現在我們需要對桶内的酒店做運算,擷取每個品牌的使用者評分的min、max、avg等值。
這就要用到Metric聚合了,例如stat聚合:就可以擷取min、max、avg等結果。
GET /hotel/_search
{
"size": 0,
"aggs": {
"brandAgg": {
"terms": {
"field": "brand",
"size": 20
},
"aggs": { // 是brands聚合的子聚合,也就是分組後對每組分别計算
"score_stats": { // 聚合名稱
"stats": { // 聚合類型,這裡stats可以計算min、max、avg等
"field": "score" // 聚合字段,這裡是score
}
}
}
}
}
}
這次的score_stats聚合是在brandAgg的聚合内部嵌套的子聚合。因為我們需要在每個桶分别計算。
另外,我們還可以給聚合結果做個排序,例如按照每個桶的酒店平均分做排序:
12.自動補全查詢
elasticsearch提供了Completion Suggester查詢來實作自動補全功能。這個查詢會比對以使用者輸入内容開頭的詞條并傳回。為了提高補全查詢的效率,對于文檔中字段的類型有一些限制:
- 參與補全查詢的字段必須是completion類型。
- 字段的内容一般是用來補全的多個詞條形成的數組。
比如,一個這樣的索引庫:
// 建立索引庫
PUT test
{
"mappings": {
"properties": {
"title":{
"type": "completion"
}
}
}
}
// 示例資料
POST test/_doc
{
"title": ["Sony", "WH-1000XM3"]
}
POST test/_doc
{
"title": ["SK-II", "PITERA"]
}
POST test/_doc
{
"title": ["Nintendo", "switch"]
}
// 自動補全查詢
GET /test/_search
{
"suggest": {
"title_suggest": {
"text": "s", // 關鍵字
"completion": {
"field": "title", // 補全查詢的字段
"skip_duplicates": true, // 跳過重複的
"size": 10 // 擷取前10條結果
}
}
}
}