1. 程式人生 > 程式設計 >python 使用elasticsearch 實現翻頁的三種方式

python 使用elasticsearch 實現翻頁的三種方式

python 使用elasticsearch 實現翻頁的三種方式

使用ES做搜尋引擎拉取資料的時候,如果資料量太大,通過傳統的from + size的方式並不能獲取所有的資料(預設最大記錄數10000),因為隨著頁數的增加,會消耗大量的記憶體,導致ES叢集不穩定。因此延伸出了scroll,search_after等翻頁方式。

一、from + size 淺分頁

"淺"分頁可以理解為簡單意義上的分頁。它的原理很簡單,就是查詢前20條資料,然後截斷前10條,只返回10-20的資料。這樣其實白白浪費了前10條的查詢。

GET test/_search
{
 "query": {
  "bool": {
   "filter": [
    {
     "term": {
      "age": 28
     }
    }
   ]
  }
 },"size": 10,"from": 20,"sort": [
  {
   "timestamp": {
    "order": "desc"
   },"_id": {
    "order": "desc"
   }
  }
 ]
}

from定義了目標資料的偏移值,size定義當前返回的數目。預設from為0,size為10,即所有的查詢預設僅僅返回前10條資料。

在這裡有必要了解一下from/size的原理:
因為es是基於分片的,假設有5個分片,from=100,size=10。則會根據排序規則從5個分片中各取回100條資料資料,然後彙總成500條資料後選擇最後面的10條資料。

做過測試,越往後的分頁,執行的效率越低。總體上會隨著from的增加,消耗時間也會增加。而且資料量越大,就越明顯!

二、scroll 深分頁

from+size查詢在10000-50000條資料(1000到5000頁)以內的時候還是可以的,但是如果資料過多的話,就會出現深分頁問題。為了解決上面的問題,elasticsearch提出了一個scroll滾動的方式。

scroll 類似於sql中的cursor,使用scroll,每次只能獲取一頁的內容,然後會返回一個scroll_id。根據返回的這個scroll_id可以不斷地獲取下一頁的內容,所以scroll並不適用於有跳頁的情景。

# -*- coding: utf-8 -*-
# @Time  : 
# @Author :
 
from elasticsearch import Elasticsearch
 
es = Elasticsearch(hosts="ip:9200",timeout=20,max_retries=10,retry_on_timeout=True)
 
# Elasticsearch 需要保持搜尋的上下文環境多久 遊標查詢過期時間為10分鐘(10m)
page = es.search(
        index="source_keyword_message",doc_type="source_keyword_message",scroll='10m',size=100,body={
          "query": {"match_all": {}},}
      )
# 遊標用於輸出es查詢出的所有結果
sid = page['_scroll_id']
# es查詢出的結果總量
scroll_size = page['hits']['total']
# es查詢出的結果第一頁
datas = page.get('hits').get('hits')
 
while (scroll_size > 0):
   page = es.scroll(scroll_id=sid,scroll='5m')
   sid = page['_scroll_id']
   scroll_size = len(page['hits']['hits'])
   datas = page.get('hits').get('hits')
   
   
  1. scroll=5m表示設定scroll_id保留5分鐘可用。
  2. 使用scroll必須要將from設定為0。預設0
  3. size決定後面每次呼叫_search搜尋返回的數量

三、search_after 深分頁

scroll 的方式,官方的建議不用於實時的請求(一般用於資料匯出),因為每一個 scroll_id 不僅會佔用大量的資源,而且會生成歷史快照,對於資料的變更不會反映到快照上。

search_after 分頁的方式是根據上一頁的最後一條資料來確定下一頁的位置,同時在分頁請求的過程中,如果有索引資料的增刪改查,這些變更也會實時的反映到遊標上。但是需要注意,因為每一頁的資料依賴於上一頁最後一條資料,所以無法跳頁請求。

為了找到每一頁最後一條資料,每個文件必須有一個全域性唯一值,官方推薦使用 _uid 作為全域性唯一值,其實使用業務層的 id 也可以。

GET test/_search
{
 "query": {
  "bool": {
   "filter": [
    {
     "term": {
      "age": 28
     }
    }
   ]
  }
 },"size": 20,"from": 0,"_id": {
    "order": "desc"
   }
  }
 ]
}
  1. 使用search_after必須要設定from=0。
  2. 這裡我使用timestamp和_id作為唯一值排序。
  3. 我們在返回的最後一條資料裡拿到sort屬性的值傳入到search_after。

使用sort返回的值搜尋下一頁:

GET test/_search
{
 "query": {
  "bool": {
   "filter": [
    {
     "term": {
      "age": 28
     }
    }
   ]
  }
 },"search_after": [
  1541495312521,"d0xH6GYBBtbwbQSP0j1A"
 ],"_id": {
    "order": "desc"
   }
  }
 ]
}

到此這篇關於python 使用elasticsearch 實現翻頁的三種方式的文章就介紹到這了,更多相關python elasticsearch 翻頁內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!