1. 程式人生 > >es深度分頁查詢

es深度分頁查詢

前言

    近期在做新的專案時,使用了ElasticSearch作為資料的儲存和查詢。接到了一個比較噁心的需求,需要對es進行分頁查詢,單次查詢一萬條,最多需要查詢十次。當時也沒想太多,需求評審時並沒有及時反駁,既然掉坑裡了,那就想辦法爬出來吧!

es的分頁

1)from+size淺分頁

    我們當時有點想當然了,以為from+size就可以搞定(業務程式碼寫多的後果)。實際測試的時候,發現記憶體消耗特別大,而且速度也很一般。ES的查詢機制如下:

    假設我們的ES有三個節點,當分頁查詢請求過來時,如果落到node1節點,那麼node1節點將會向node2和node3傳送同樣的查詢請求,每個節點將topN的文件返回(這裡只返回文件的id以及打分排序的欄位,減少資料傳輸),node1會對三個節點的所有文件(3*N個)進行排序,取topN後再根據文件的id到對應的節點上查詢整個文件資料,最後返回客戶端。

    而對於分頁查詢,比如from=10000,szie=10000,其實每個節點需要查詢from+size=20000條資料,排序之後擷取後10000條資料。當我們進行深度分頁,比如查詢第十頁資料時,每個節點需要查詢10*size=10W條資料,這個太恐怖了。而且預設情況下,當from+size大於10000時,查詢會丟擲一個異常,ES2.0後有一個max_result_window屬性的設定,預設值是10000,也就是from+size的最大限度。當然你可以修改這個值作為臨時的應對策略,不過治標不治本,產品也只會變本加厲!

2)scroll查詢

    ES支援scroll滾屏查詢,有興趣的同學可以瞭解一下,網上相關的文件不少。不過根據ES官網的描述,scroll查詢是很耗效能的方式,不建議在實時查詢中運用。摘抄自官網:

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.

3)search_after查詢

    search_after是ES5.0及之後版本提供的新特性,search_after有點類似scroll,但是和scroll又不一樣,它提供一個活動的遊標,通過上一次查詢最後一條資料來進行下一次查詢。

 

    比如第一次查詢如下:

GET zm/recall/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "lastModifyTime": {
        "order": "desc"
      }
    }
  ], 
  "size": 10
}

 

    這裡根據更新時間進行排序,拿到的結果如下:

{
        "_index": "zmrecall",
        "_type": "recall",
        "_id": "60310505115909",
        "_score": null,
        "_source": {
          "userId": 60310505115909,
          "score": 1,
          "city": [
            276
          ],
          "sex": 1,
          "age": 29,
          "lastModifyTime": 1545037514
        },
        "sort": [
          1545037514
        ]
      }

 

    注意到返回結果中有一個sort欄位,所以下一次查詢的時候,只需要將本次查詢最後一條資料中的排序欄位加入查詢即可:

GET zm/recall/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "lastModifyTime": {
        "order": "desc"
      }
    }
  ], 
  "search_after": [1545037514],//這個值與上次查詢最後一條資料的sort值一致,支援多個
  "size": 10
}

    這裡需要說明一下,使用search_after查詢需要將from設定為0或-1,當然你也可以不寫

 

    另外在ES6.5的文件中有這樣一句話需要注意一下:

    大致的意思就是,如果search_after中的關鍵字為654,那麼654323的文件也會被搜尋到,所以在選擇search_after的排序欄位時需要謹慎,可以使用比如文件的id或者時間戳等

 

    另外,search_after並不是隨機的查詢某一頁資料,而是並行的滾屏查詢;search_after的查詢順序會在更新和刪除時發生變化,也就是說支援實時的資料查詢

總結

    在使用一個工具之前,一定要對其內部的基本流程有一個簡單的瞭解,否則出現問題時不知從何入手。search_after相比較上面的淺分頁以及scroll滾屏查詢會有很大的效能提升,推薦大家使用!

最後附上ES的官方文件:https://www.elastic.co/guide/en/elasticsearch/reference/6.5/search-request-search-after.html

另外在csdn上也看到一個部落格,講的很不錯:https://blog.csdn.net/ctwy291314/article/details/82754652