1. from+size 實現(xiàn)分頁
from表示從第幾行開始,size表示查詢多少條文檔坊秸。from默認為0踱蠢,size默認為10,
注意:size的大小不能超過index.max_result_window這個參數(shù)的設(shè)置咪辱,默認為10,000振劳。
如果搜索size大于10000,需要設(shè)置index.max_result_window參數(shù)
PUT _settings
{
"index": {
"max_result_window": "10000000"
}
}
內(nèi)部執(zhí)行原理:
示例:有三個節(jié)點node1油狂、node2历恐、node3,每個節(jié)點上有2個shard分片
node1 | node2 | node3 |
---|---|---|
shard1 | shard3 | shard5 |
shard2 | shard4 | shard6 |
1.client發(fā)送分頁查詢請求到node1(coordinating node)上专筷,node1建立一個大小為from+size的優(yōu)先級隊列來存放查詢結(jié)果弱贼;
2.node1將請求廣播到涉及到的shards上;
3.每個shards在內(nèi)部執(zhí)行查詢磷蛹,把from+size條記錄存到內(nèi)部的優(yōu)先級隊列(top N表)中吮旅;
4.每個shards把緩存的from+size條記錄返回給node1;
5.node1獲取到各個shards數(shù)據(jù)后味咳,進行合并并排序庇勃,選擇前面的 from + size 條數(shù)據(jù)存到優(yōu)先級隊列,以便 fetch 階段使用槽驶。
各個分片返回給 coordinating node 的數(shù)據(jù)用于選出前 from + size 條數(shù)據(jù)责嚷,所以,只需要返回唯一標記 doc 的 _id 以及用于排序的 _score 即可掂铐,這樣也可以保證返回的數(shù)據(jù)量足夠小罕拂。
coordinating node 計算好自己的優(yōu)先級隊列后揍异,query 階段結(jié)束,進入 fetch 階段爆班。
from+size在深度分頁時衷掷,會帶來嚴重的性能問題:
CPU、內(nèi)存柿菩、IO戚嗅、網(wǎng)絡(luò)帶寬
數(shù)據(jù)量越大,越往后翻頁碗旅,性能越低
2.scroll
可以把 scroll 理解為關(guān)系型數(shù)據(jù)庫里的 cursor渡处,因此,scroll 并不適合用來做實時搜索祟辟,而更適用于后臺批處理任務(wù)颜价,比如群發(fā)骆莹。
可以把 scroll 分為初始化和遍歷兩步蚜印,
初始化時將所有符合搜索條件的搜索結(jié)果緩存起來循捺,可以想象成快照,
遍歷時吼具,從這個快照里取數(shù)據(jù)僚纷,也就是說,在初始化后對索引插入拗盒、刪除怖竭、更新數(shù)據(jù)都不會影響遍歷結(jié)果。
1.初始化:
POST http://192.168.18.230:9200/bill/bill/_search?scroll=3m
{
"query": { "match_all": {}},
"size": 10
}
參數(shù) scroll陡蝇,表示暫存搜索結(jié)果的時間
返回一個 _scroll_id痊臭,_scroll_id 用來下次取數(shù)據(jù)用
2.遍歷:
POST http://192.168.18.230:9200/_search?scroll=3m
{
"scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAHRCFi1BLWIzSHdhUkl1cC1rcjBueVhJZUEAAAAAAAB0QRYtQS1iM0h3YVJJdXAta3IwbnlYSWVBAAAAAAAAdEQWLUEtYjNId2FSSXVwLWtyMG55WEllQQAAAAAAAHRDFi1BLWIzSHdhUkl1cC1rcjBueVhJZUEAAAAAAAB0RRYtQS1iM0h3YVJJdXAta3IwbnlYSWVB"
}
這里的 scroll_id 即 上一次遍歷取回的 _scroll_id 或者是初始化返回的 _scroll_id,同樣的登夫,需要帶 scroll 參數(shù)广匙。
注意,每次都要傳參數(shù) scroll恼策,刷新搜索結(jié)果的緩存時間鸦致。另外,不需要指定 index 和 type涣楷。
3.search_after
官網(wǎng)上的說明:
The Scroll api is recommended for efficient deep scrolling but scroll contexts are costly and it is not recommended to use it for real time user requests.
The search_after parameter circumvents this problem by providing a live cursor. The idea is to use the results from the previous page to help the retrieval of the next page.
Scroll 被推薦用于深度查詢分唾,但是contexts的代價是昂貴的,不推薦用于實時用戶請求总棵,而更適用于后臺批處理任務(wù)鳍寂,比如群發(fā)。
search_after 提供了一個實時的光標來避免深度分頁的問題情龄,其思想是使用前一頁的結(jié)果來幫助檢索下一頁迄汛。
search_after 需要使用一個唯一值的字段作為排序字段,否則不能使用search_after方法
推薦使用_uid 作為唯一值的排序字段
GET twitter/tweet/_search
{
"size": 10,
"query": { "match_all": {}},
"sort": [
{"date": "asc"},
{"_uid": "desc"}
]
}
每一條返回記錄中會有一組 sort values 骤视,查詢下一頁時鞍爱,在search_after參數(shù)中指定上一頁返回的 sort values
GET twitter/tweet/_search
{
"size": 10,
"query": { "match_all": {}},
"search_after": [1463538857, "tweet#654323"],
"sort": [
{"date": "asc"},
{"_uid": "desc"}
]
}
注意:search_after不能自由跳到一個隨機頁面,只能按照 sort values 跳轉(zhuǎn)到下一頁
4.總結(jié)
- 深度分頁不管是關(guān)系型數(shù)據(jù)庫還是Elasticsearch還是其他搜索引擎专酗,都會帶來巨大性能開銷睹逃,特別是在分布式情況下。
- 有些問題可以考業(yè)務(wù)解決而不是靠技術(shù)解決祷肯,比如很多業(yè)務(wù)都對頁碼有限制沉填,google 搜索,往后翻到一定頁碼就不行了佑笋。
- scroll 并不適合用來做實時搜索翼闹,而更適用于后臺批處理任務(wù),比如群發(fā)蒋纬。
- search_after不能自由跳到一個隨機頁面猎荠,只能按照 sort values 跳轉(zhuǎn)到下一頁。