elasticsearch 深度分頁問題

elasticsearch分頁對於用過es的人應該都會使用 ,和數據庫的分頁類似,如下所示,通過from + size可以對數據進行分頁。

{
    "from" : 0, 
    "size" : 10,
    "query" : {
        "term" : { "user" : "dejun" }
    }
} 

可以查詢1-10條記錄,不過由於es是分佈式的,數據都是分佈在多個分片上。
如查詢: from = 990 , size = 10 , 分片數爲:4 ,那麼es是如何 查詢的呢? 如下圖所示:

在這裏插入圖片描述

  • es會在每個分片獲取1000條文檔,通過Coordinating Node 彙總各個節點的數據,再通過排序選擇前1000個文檔返回。
  • 所以當頁數越深,查詢的節點的數量越大,自然佔用的內存也越多,那麼我們是不是可以把系統內存查爆? ES爲了避免深度分頁帶來的內存開銷,ES默認限定只能查詢10000個文檔

那麼我們做個示範:

POST  /demo/_search
{
  "from" : 0 ,
  "size" : 10001 ,
  "query" : {
			"match_all":{}
}
}

ES會報以下錯誤:
Result window is too large, from + size must be less than or equal to: [10000] but was [10001]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level parameter.

以上可見,from + size 這種方式不適用於深度分頁場景,下面介紹其它兩種分頁方式…

  • Search After
  • Scroll Api

Search After

  • 可以避免深度分頁帶來的性能問題,可以實時的獲取下一頁文檔
  • 不支持指定頁數,只能向下翻
  • 需要加入排序 sort,並且排序的字段一定要是唯一的

示例:

POST /demo/_search
{
  
   "size": 3, 
  "query": {
    "terms": {
      "txAcctNo": ["11111"
]
    }
  },
  "sort" :{
    "_id" :"desc"
  }
}

ES返回:

{
  "took": 110,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1122,
    "max_score": null,
    "hits": [
      {
        
        "_id": "6140202001021427303890174574324",
        "_score": null,
        "_source": {
        
        },
        "sort": [
          "6140202001021427303890174574324"
        ]
      },
      {
       
        "_id": "6140201912131352403980169574091",
        "_score": null,
        "_source": {
          
        },
        "sort": [
          "6140201912131352403980169574091"
        ]
      },
      {
    
        "_id": "6140201912101038085680169566509",
        "_score": null,
        "_source": {
         
        },
        "sort": [
          "6140201912101038085680169566509"
        ]
      }
    ]
  }
}

每條數據都會有一個sort返回,只需要在下一次查詢中,在search_after中加入這個值,如下:

POST /demo/_search
{
  
   "size": 3, 
  "query": {
    "terms": {
      "txAcctNo": ["11111"
]
    }
  },
  "sort" :{
    "_id" :"desc"
    
  },
  "search_after" :[
          "6140202001171118484170182578541"
        ]
}

以上即是search_after的用法,其實很簡單,那麼爲什麼search_afterr適合深度分頁呢,來看一下原理:

假設size:10 ,查詢10000-10010,search_after會通過唯一排序的值定位,每個節點只會查10條數據,避免了內存開銷過大的問題
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章