elasticserach数据库深度分页查询的原理
深度分頁存在的問題
https://segmentfault.com/a/1190000019004316?utm_source=tag-newest
在實際應(yīng)用中,分頁是必不可少的,例如,前端頁面展示數(shù)據(jù)給用戶往往都是分頁進行展示的。
1、ES分頁搜索
Elasticsearch分頁搜索采用的是from+size。from表示查詢結(jié)果的起始下標,size表示從起始下標開始返回文檔的個數(shù)。
示例:
什么是深分頁(deep paging)?簡單來說,就是搜索的特別深,比如總共有60000條數(shù)據(jù),三個primary shard,每個shard上分了20000條數(shù)據(jù),每頁是10條數(shù)據(jù),這個時候,你要搜索到第1000頁,實際上要拿到的是10001~10010。
注意這里千萬不要理解成每個shard都是返回10條數(shù)據(jù)。這樣理解是錯誤的!
下面做一下詳細的分析:
請求首先可能是打到一個不包含這個index的shard的node上去,這個node就是一個協(xié)調(diào)節(jié)點coordinate node,那么這個coordinate node就會將搜索請求轉(zhuǎn)發(fā)到index的三個shard所在的node上去。比如說我們之前說的情況下,要搜索60000條數(shù)據(jù)中的第1000頁,實際上每個shard都要將內(nèi)部的20000條數(shù)據(jù)中的第10001~10010條數(shù)據(jù),拿出來,不是才10條,是10010條數(shù)據(jù)。3個shard的每個shard都返回10010條數(shù)據(jù)給協(xié)調(diào)節(jié)點coordinate node,coordinate node會收到總共30030條數(shù)據(jù),然后在這些數(shù)據(jù)中進行排序,根據(jù)_score相關(guān)度分數(shù),然后取到10001~10010這10條數(shù)據(jù),就是我們要的第1000頁的10條數(shù)據(jù)。
如下圖所示:
deep paging問題就是說from + size分頁太深,那么每個shard都要返回大量數(shù)據(jù)給coordinate node協(xié)調(diào)節(jié)點,會消耗大量的帶寬,內(nèi)存,CPU。
深度分頁問題之所以存在,是和Elasticsearch搜索內(nèi)部執(zhí)行原理分不開的。
如果你想查詢第5000-5100數(shù)據(jù),查詢官網(wǎng)API你很容易就知道,發(fā)送如下查詢條件就可以做到:
POST auditlog_operation/operlog/_search
{
“from”:5000 //from:定義從哪里開始拿數(shù)據(jù)
“size”:100 //size:定義一共拿多少條數(shù)據(jù)
}
查詢流程如下:
客戶端發(fā)送請求到某個node節(jié)點。
此node將請求廣播到各分片,各分片各自查詢前5100條數(shù)據(jù)。
查詢結(jié)果返回給node節(jié)點,node對結(jié)果進行合并整合,取出前5100條數(shù)據(jù)。
返回給客戶端。
流程大概如下
相信就算是技術(shù)小白也能看出上述深度分頁查詢的問題,如果你要深度獲取1000000到1000100頁的數(shù)據(jù),性能問題會非常明顯的暴露出來:CPU、內(nèi)存、IO、網(wǎng)絡(luò)帶寬等等,而且Elasticsearch本身就是個Java應(yīng)用,若并發(fā)上去,Elasticsearch會快就會OOM
{
"query": {
"match_all": {}
},
"from": 9990,
"size": 10
}
{
"query": {
"match_all": {}
},
"from": 9999,
"size": 10
}
我們在獲取第9999條到10009條數(shù)據(jù)的時候,其實每個分片都會拿到10009條數(shù)據(jù),然后集合在一起,總共是10009*3=30027條數(shù)據(jù),針對30027數(shù)據(jù)再次做排序處理,最終會獲取最后10條數(shù)據(jù)。
如此一來,搜索得太深,就會造成性能問題,會耗費內(nèi)存和占用cpu。而且es為了性能,他不支持超過一萬條數(shù)據(jù)以上的分頁查詢。那么如何解決深度分頁帶來的性能呢?其實我們應(yīng)該避免深度分頁操作(限制分頁頁數(shù)),比如最多只能提供100頁的展示,從第101頁開始就沒了,畢竟用戶也不會搜的那么深,我們平時搜索淘寶或者百度,一般也就看個10來頁就頂多了。
查詢請求:
POST auditlog_operation/operlog/_search
{
“from”:10000
“size”:100
}
如果你嘗試發(fā)送上述from+size請求來獲取10000-10100條數(shù)據(jù),對不起會返回錯誤:
如果你嘗試發(fā)送上述from+size請求來獲取10000-10100條數(shù)據(jù),對不起會返回錯誤:
{"error":{"root_cause":[{"type":"query_phase_execution_exception","reason":"Resultwindow is too large, from + size must be less than or equal to: [1000000] butwas [1000100]. See the scroll api for a more efficient way to request largedata sets. This limit can be set by changing the [index.max_result_window]index levelparameter."}],"type":"search_phase_execution_exception","reason":"allshards failed","phase":"query_fetch","grouped":true,"failed_shards":[{"shard":0,"index":"auditlog_operation","node":"iqu-KVKjTRmT3YcT9XAu_w","reason":{"type":"query_phase_execution_exception","reason":"Resultwindow is too large, from + size must be less than or equal to: [1000000] butwas [1000100]. See the scroll api for a more efficient way to request largedata sets. This limit can be set by changing the [index.max_result_window]index level parameter."}}]},"status":500}
迅速查詢官網(wǎng)得到更明確的提示:
翻譯成中文為:注意 from+size不再適用于查詢數(shù)據(jù)超過index.max_result_window設(shè)置值,此默認值為10000。查看 Scroll 或 Search After來獲取更高效的深層分頁(滾動)。
由此可以得到兩個結(jié)論:
你可以修改index.max_result_window設(shè)置值來繼續(xù)使用from+size做分頁查詢。當(dāng)然效率肯定不高。
如果要找更高效的深度分頁方式,請使用Scroll 或者Search After。
Scroll API
Scroll API更適用于檢索大量數(shù)據(jù)(甚至全部數(shù)據(jù))。它先做一個初始階段搜索然后持續(xù)批量從Elasticsearch里拉取結(jié)果直到返回結(jié)果為空。這有點像傳統(tǒng)數(shù)據(jù)庫里的cursors(游標)。
https://blog.csdn.net/lisongjia123/article/details/79041402
https://www.sohu.com/a/165387407_465944
https://segmentfault.com/a/1190000019004316?utm_source=tag-newest
除了效率上的問題,還有一個無法解決的問題是,es 目前支持最大的 skip 值是 max_result_window ,默認
為 10000 。也就是當(dāng) from + size > max_result_window 時,es 將返回錯誤
[root@dnsserver ~]# curl -XGET 127.0.0.1:9200/custm/_settings?pretty
{
"custm" : {
"settings" : {
"index" : {
"max_result_window" : "50000",
....
}
}
}
}
最開始的時候是線上客戶的es數(shù)據(jù)出現(xiàn)問題,當(dāng)分頁到幾百頁的時候,es 無法返回數(shù)據(jù),此時為了恢復(fù)正常使用,我們采用了緊急規(guī)避方案,就是將 max_result_window 的值調(diào)至 50000,其中custm是索引的名稱,http請求提交的方式必須是put請求
[root@dnsserver ~]# curl -XPUT "127.0.0.1:9200/custm/_settings" -d
'{
"index" : {
"max_result_window" : 50000
}
}'
然后這種方式只能暫時解決問題,當(dāng)es 的使用越來越多,數(shù)據(jù)量越來越大,深度分頁的場景越來越復(fù)雜時,如何解決這種問題呢?
custm
總結(jié)
以上是生活随笔為你收集整理的elasticserach数据库深度分页查询的原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 键盘上各种符号的英文读法
- 下一篇: 招行信用卡循环利息是什么 要怎么计算