Elasticsearch Search After分頁查詢所有數(shù)據(jù)的實(shí)現(xiàn)方式
search_after 分頁的方式是根據(jù)上一頁的最后一條數(shù)據(jù)來確定下一頁的位置,同時(shí)在分頁請(qǐng)求的過程中,如果有索引數(shù)據(jù)的增刪改查,這些變更也會(huì)實(shí)時(shí)的反映到游標(biāo)上。但是需要注意,因?yàn)槊恳豁摰臄?shù)據(jù)依賴于上一頁最后一條數(shù)據(jù),所以無法跳頁請(qǐng)求。
為了找到每一頁最后一條數(shù)據(jù),每個(gè)文檔必須有一個(gè)全局唯一值,官方推薦使用 _uid 作為全局唯一值,其實(shí)使用業(yè)務(wù)層的 id 也可以。
上面的請(qǐng)求會(huì)為每一個(gè)文檔返回一個(gè)包含sort排序值的數(shù)組。這些sort排序值可以被用于 search_after 參數(shù)里以便抓取下一頁的數(shù)據(jù)。比如,我們可以使用最后的一個(gè)文檔的sort排序值,將它傳遞給 search_after 參數(shù):
注意:當(dāng)我們使用search_after時(shí),from值必須設(shè)置為0或者-1。
search_after缺點(diǎn)是不能夠隨機(jī)跳轉(zhuǎn)分頁,只能是一頁一頁的向后翻,并且需要至少指定一個(gè)唯一不重復(fù)字段來排序。它與滾動(dòng)API非常相似,但與它不同,search_after參數(shù)是無狀態(tài)的,它始終針對(duì)最新版本的搜索器進(jìn)行解析。因此,排序順序可能會(huì)在步行期間發(fā)生變化,具體取決于索引的更新和刪除。
1. search_after 查詢
search_after 查詢定義與實(shí)戰(zhàn)案例
search_after 查詢本質(zhì):使用前一頁中的一組排序值來檢索匹配的下一頁。
前置條件:使用 search_after 要求后續(xù)的多個(gè)請(qǐng)求返回與第一次查詢相同的排序結(jié)果序列。也就是說,即便在后續(xù)翻頁的過程中,可能會(huì)有新數(shù)據(jù)寫入等操作,但這些操作不會(huì)對(duì)原有結(jié)果集構(gòu)成影響。
如何實(shí)現(xiàn)呢?
可以創(chuàng)建一個(gè)時(shí)間點(diǎn) Point In Time(PIT)保障搜索過程中保留特定事件點(diǎn)的索引狀態(tài)。
- Point In Time(PIT)是 Elasticsearch 7.10 版本之后才有的新特性。
- PIT的本質(zhì):存儲(chǔ)索引數(shù)據(jù)狀態(tài)的輕量級(jí)視圖。
如下示例能很好的解讀 PIT 視圖的內(nèi)涵。
創(chuàng)建 PIT
POST kibana_sample_data_logs/_pit?keep_alive=1m
獲取數(shù)據(jù)量 14074
POST kibana_sample_data_logs/_count
新增一條數(shù)據(jù)
POST kibana_sample_data_logs/_doc/14075
{
"test":"just testing"
}數(shù)據(jù)總量為 14075
POST kibana_sample_data_logs/_count
查詢PIT,數(shù)據(jù)依然是14074,說明走的是之前時(shí)間點(diǎn)的視圖的統(tǒng)計(jì)
POST /_search
{
"track_total_hits": true,
"query": {
"match_all": {}
},
"pit": {
"id": "48myAwEXa2liYW5hX3NhbXBsZV9kYXRhX2xvZ3MWM2hGWXpxLXFSSGlfSmZIaXJWN0dxUQAWdG1TOWFMTF9UdTZHdVZDYmhoWUljZwAAAAAAAAEN3RZGOFJCMGVrZVNndTk3U1I0SG81V3R3AAEWM2hGWXpxLXFSSGlfSmZIaXJWN0dxUQAA"
}
}有了 PIT,search_after 的后續(xù)查詢都是基于 PIT 視圖進(jìn)行,能有效保障數(shù)據(jù)的一致性。
search_after 分頁查詢可以簡(jiǎn)單概括為如下幾個(gè)步驟。
Step 1: 創(chuàng)建 PIT
步驟 1:創(chuàng)建 PIT 視圖,這是前置條件不能省。
POST kibana_sample_data_logs/_pit?keep_alive=5m
返回結(jié)果如下:
{
"id" : "48myAwEXa2liYW5hX3NhbXBsZV9kYXRhX2xvZ3MWM2hGWXpxLXFSSGlfSmZIaXJWN0dxUQAWdG1TOWFMTF9UdTZHdVZDYmhoWUljZwAAAAAAAAEg5RZGOFJCMGVrZVNndTk3U1I0SG81V3R3AAEWM2hGWXpxLXFSSGlfSmZIaXJWN0dxUQAA"
}keep_alive=5m,類似scroll的參數(shù),代表視圖保留時(shí)間是 5 分鐘。
超過 5 分鐘執(zhí)行會(huì)報(bào)錯(cuò)如下:
{
"type": "search_context_missing_exception",
"reason": "No search context found for id [91600]"
}Step 2: 創(chuàng)建基礎(chǔ)查詢
步驟 2:創(chuàng)建基礎(chǔ)查詢語句,這里要設(shè)置翻頁的條件。
GET /_search
{
"size":10,
"query": {
"match" : {
"host" : "elastic"
}
},
"pit": {
"id": "48myAwEXa2liYW5hX3NhbXBsZV9kYXRhX2xvZ3MWM2hGWXpxLXFSSGlfSmZIaXJWN0dxUQAWdG1TOWFMTF9UdTZHdVZDYmhoWUljZwAAAAAAAAEg5RZGOFJCMGVrZVNndTk3U1I0SG81V3R3AAEWM2hGWXpxLXFSSGlfSmZIaXJWN0dxUQAA",
"keep_alive": "1m"
},
"sort": [
{"response.keyword": "asc"}
]
}設(shè)置了PIT,檢索時(shí)候就不需要再指定索引。
id 是基于步驟1 返回的 id 值。
排序 sort 指的是:按照哪個(gè)關(guān)鍵字排序。
在每個(gè)返回文檔的最后,會(huì)有兩個(gè)結(jié)果值,如下所示:
{
"sort": [
"200",
4
]
}其中,“200”就是我們指定的排序方式:基于 {“response.keyword”: “asc”} 升序排列。
而 4 代表什么含義呢?
4 代表——隱含的排序值,是基于_shard_doc 的升序排序方式。
官方文檔把這種隱含的字段叫做:tiebreaker (決勝字段),tiebreaker 等價(jià)于_shard_doc。
tiebreaker 本質(zhì)含義:每個(gè)文檔的唯一值,確保分頁不會(huì)丟失或者分頁結(jié)果數(shù)據(jù)出現(xiàn)重復(fù)(相同頁重復(fù)或跨頁重復(fù))。
step 3 : 開始翻頁
步驟3:實(shí)現(xiàn)后續(xù)翻頁。
GET /_search
{
"size": 10,
"query": {
"match" : {
"host" : "elastic"
}
},
"pit": {
"id": "48myAwEXa2liYW5hX3NhbXBsZV9kYXRhX2xvZ3MWM2hGWXpxLXFSSGlfSmZIaXJWN0dxUQAWdG1TOWFMTF9UdTZHdVZDYmhoWUljZwAAAAAAAAEg5RZGOFJCMGVrZVNndTk3U1I0SG81V3R3AAEWM2hGWXpxLXFSSGlfSmZIaXJWN0dxUQAA",
"keep_alive": "1m"
},
"sort": [
{"response.keyword": "asc"}
],
"search_after": [
"200",
4
]
}后續(xù)翻頁都需要借助 search_after 指定前一頁的最后一個(gè)文檔的 sort 字段值。
如下代碼所示:
{
"search_after": [
"200",
4
]
}顯然,search_after 查詢僅支持向后翻頁。
search_after 查詢優(yōu)缺點(diǎn)及適用場(chǎng)景
search_after 優(yōu)點(diǎn)
- 不嚴(yán)格受制于 max_result_window,可以無限制往后翻頁。
- ps:不嚴(yán)格含義:?jiǎn)未握?qǐng)求值不能超過 max_result_window;但總翻頁結(jié)果集可以超過。
search_after 缺點(diǎn)
- 只支持向后翻頁,不支持隨機(jī)翻頁。
search_after 適用場(chǎng)景
- 類似:今日頭條分頁搜索 https://m.toutiao.com/search
- 不支持隨機(jī)翻頁,更適合手機(jī)端應(yīng)用的場(chǎng)景。
2. Scroll 遍歷查詢
Scroll 遍歷查詢定義與實(shí)戰(zhàn)案例
相比于 From + size 和 search_after 返回一頁數(shù)據(jù),Scroll API 可用于從單個(gè)搜索請(qǐng)求中檢索大量結(jié)果(甚至所有結(jié)果),其方式與傳統(tǒng)數(shù)據(jù)庫(kù)中游標(biāo)(cursor)類似。
如果把 From + size 和 search_after 兩種請(qǐng)求看做近實(shí)時(shí)的請(qǐng)求處理方式,那么 scroll 滾動(dòng)遍歷查詢顯然是非實(shí)時(shí)的。數(shù)據(jù)量大的時(shí)候,響應(yīng)時(shí)間可能會(huì)比較長(zhǎng)。
scroll 核心執(zhí)行步驟如下:
步驟 1:指定檢索語句同時(shí)設(shè)置 scroll 上下文保留時(shí)間。
實(shí)際上,scroll 已默認(rèn)包含了 search_after 的PIT 的視圖或快照功能。
從 Scroll 請(qǐng)求返回的結(jié)果反映了發(fā)出初始搜索請(qǐng)求時(shí)索引的狀態(tài),類似在那一個(gè)時(shí)刻做了快照。隨后對(duì)文檔的更改(寫入、更新或刪除)只會(huì)影響以后的搜索請(qǐng)求。
POST kibana_sample_data_logs/_search?scroll=3m
{
"size": 100,
"query": {
"match": {
"host": "elastic"
}
}
}步驟 2:向后翻頁繼續(xù)獲取數(shù)據(jù),直到?jīng)]有要返回的結(jié)果為止。
POST _search/scroll
{
"scroll" : "3m",
"scroll_id":"FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFkY4UkIwZWtlU2d1OTdTUjRIbzVXdHcAAAAAAAGmkBZ0bVM5YUxMX1R1Nkd1VkNiaGhZSWNn"
}scroll_id 值是步驟 1 返回的結(jié)果值。
Scroll 遍歷查詢優(yōu)缺點(diǎn)及適用場(chǎng)景
scroll 查詢優(yōu)點(diǎn)
- 支持全量遍歷。
- ps:?jiǎn)未伪闅v的 size 值也不能超過 max_result_window 大小。
scroll 查詢?nèi)秉c(diǎn)
- 響應(yīng)時(shí)間非實(shí)時(shí)。
- 保留上下文需要足夠的堆內(nèi)存空間。
scroll 查詢適用場(chǎng)景
- 全量或數(shù)據(jù)量很大時(shí)遍歷結(jié)果數(shù)據(jù),而非分頁查詢。
- 官方文檔強(qiáng)調(diào):不再建議使用scroll API進(jìn)行深度分頁。如果要分頁檢索超過 Top 10,000+ 結(jié)果時(shí),推薦使用:PIT + search_after。
總結(jié)
From+ size:需要隨機(jī)跳轉(zhuǎn)不同分頁(類似主流搜索引擎)、Top 10000 條數(shù)據(jù)之內(nèi)分頁顯示場(chǎng)景。search_after:僅需要向后翻頁的場(chǎng)景及超過Top 10000 數(shù)據(jù)需要分頁場(chǎng)景。Scroll:需要遍歷全量數(shù)據(jù)場(chǎng)景 。max_result_window:調(diào)大治標(biāo)不治本,不建議調(diào)過大。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳述 DB2 分頁查詢及 Java 實(shí)現(xiàn)的示例
本篇文章主要介紹了詳述 DB2 分頁查詢及 Java 實(shí)現(xiàn)的示例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09
SpringMVC HttpMessageConverter報(bào)文信息轉(zhuǎn)換器
??HttpMessageConverter???,報(bào)文信息轉(zhuǎn)換器,將請(qǐng)求報(bào)文轉(zhuǎn)換為Java對(duì)象,或?qū)ava對(duì)象轉(zhuǎn)換為響應(yīng)報(bào)文。???HttpMessageConverter???提供了兩個(gè)注解和兩個(gè)類型:??@RequestBody,@ResponseBody???,??RequestEntity,ResponseEntity??2023-01-01
SpringBoot整合Swagger頁面禁止訪問swagger-ui.html方式
本文介紹了如何在SpringBoot項(xiàng)目中通過配置SpringSecurity和創(chuàng)建攔截器來禁止訪問SwaggerUI頁面,此外,還提供了禁用SwaggerUI和Swagger資源的配置方法,以確保這些端點(diǎn)和頁面對(duì)外部用戶不可見或無法訪問2025-02-02
詳解SpringBoot 應(yīng)用如何提高服務(wù)吞吐量
這篇文章主要介紹了Spring Boot 應(yīng)用如何提高服務(wù)吞吐量,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
SpringBoot發(fā)送html郵箱驗(yàn)證碼功能
這篇文章主要介紹了SpringBoot發(fā)送html郵箱驗(yàn)證碼,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-12-12
SpringMVC框架實(shí)現(xiàn)Handler處理器的三種寫法
這篇文章主要介紹了SpringMVC框架實(shí)現(xiàn)Handler處理器的三種寫法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02

