第十一章 分布式搜索引擎 elasticsearch
七、搜索結果處理
- 搜索的結果可以按照用戶指定的方式去處理或展示。
1. 排序
- elasticsearch 默認是根據相關度算分(_score)來排序,但是也支持自定義方式對搜索結果排序。可以排序字段類型有:keyword 類型、數值類型、地理坐標類型、日期類型等。
1.1 普通字段排序
-
keyword、數值、日期類型排序的語法基本一致。
-
語法:
GET /indexName/_search
{"query": {"match_all": {}},"sort": [{"FIELD": "desc" // 排序字段、排序方式ASC、DESC}]
}
- 排序條件是一個數組,也就是可以寫多個排序條件。按照聲明的順序,當第一個條件相等時,再按照第二個條件排序,以此類推
1.2 地理坐標排序
- 地理坐標排序略有不同。
1.2.1 語法說明
GET /indexName/_search
{"query": {"match_all": {}},"sort": [{"_geo_distance" : {"FIELD" : "緯度,經度", // 文檔中geo_point類型的字段名、目標坐標點"order" : "asc", // 排序方式"unit" : "km" // 排序的距離單位}}]
}
-
這個查詢的含義是:
- 指定一個坐標,作為目標點
- 計算每一個文檔中,指定字段(必須是 geo_point 類型)的坐標到目標點的距離是多少
- 根據距離排序
1.2.2 示例
-
需求描述:實現對酒店數據按照到你的位置坐標的距離升序排序
-
提示:獲取你的位置的經緯度的方式:https://lbs.amap.com/demo/jsapi-v2/example/map/click-to-get-lnglat/
-
假設我的位置是:31.034661,121.612282,尋找我周圍距離最近的酒店。
2. 分頁
-
elasticsearch 默認情況下只返回 top10 的數據。而如果要查詢更多數據就需要修改分頁參數了。elasticsearch 中通過修改 from、size 參數來控制要返回的分頁結果:
- from:從第幾個文檔開始
- size:總共查詢幾個文檔
-
類似于 mysql 中的
limit ?, ?
2.1 基本的分頁
- 分頁的基本語法如下:
GET /hotel/_search
{"query": {"match_all": {}},"from": 0, // 分頁開始的位置,默認為0"size": 10, // 期望獲取的文檔總數"sort": [{"price": "asc"}]
}
2.2 深度分頁問題
- 現在,我要查詢 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 形成快照,保存在內存。官方已經不推薦使用。
2.3 小結
-
分頁查詢的常見實現方案以及優缺點:
-
from + size
:- 優點:支持隨機翻頁
- 缺點:深度分頁問題,默認查詢上限(from + size)是 10000
- 場景:百度、京東、谷歌、淘寶這樣的隨機翻頁搜索
-
after search
:- 優點:沒有查詢上限(單次查詢的 size 不超過 10000)
- 缺點:只能向后逐頁查詢,不支持隨機翻頁
- 場景:沒有隨機翻頁需求的搜索,例如手機向下滾動翻頁
-
scroll
:- 優點:沒有查詢上限(單次查詢的 size 不超過 10000)
- 缺點:會有額外內存消耗,并且搜索結果是非實時的
- 場景:海量數據的獲取和遷移。從 ES7.1 開始不推薦,建議用 after search 方案。
-
3. 高亮
3.1 高亮原理
-
什么是高亮顯示呢?
-
我們在百度,京東搜索時,關鍵字會變成紅色,比較醒目,這叫高亮顯示:
-
高亮顯示的實現分為兩步:
- 給文檔中的所有關鍵字都添加一個標簽,例如
<em>
標簽 - 頁面給
<em>
標簽編寫 CSS 樣式
- 給文檔中的所有關鍵字都添加一個標簽,例如
3.2 實現高亮
- 高亮的語法:
GET /hotel/_search
{"query": {"match": {"FIELD": "TEXT" // 查詢條件,高亮一定要使用全文檢索查詢}},"highlight": {"fields": { // 指定要高亮的字段"FIELD": {"pre_tags": "<em>", // 用來標記高亮字段的前置標簽"post_tags": "</em>" // 用來標記高亮字段的后置標簽}}}
}
-
注意:
- 高亮是對關鍵字高亮,因此搜索條件必須帶有關鍵字,而不能是范圍這樣的查詢。
- 默認情況下,高亮的字段,必須與搜索指定的字段一致,否則無法高亮
- 如果要對非搜索字段高亮,則需要添加一個屬性:required_field_match=false
-
示例:
4. 總結
-
查詢的 DSL 是一個大的 JSON 對象,包含下列屬性:
- query:查詢條件
- from 和 size:分頁條件
- sort:排序條件
- highlight:高亮條件
-
示例: