Elasticsearch——分頁查詢From&Size VS scroll

来源:http://www.cnblogs.com/xing901022/archive/2016/03/16/5284902.html
-Advertisement-
Play Games

Elasticsearch中數據都存儲在分片中,當執行搜索時每個分片獨立搜索後,數據再經過整合返回。那麼,如果要實現分頁查詢該怎麼辦呢? 更多內容參考 "Elasticsearch資料彙總" 按照一般的查詢流程來說,如果我想查詢前10條數據: 1 客戶端請求發給某個節點 2 節點轉發給個個分片,查詢


Elasticsearch中數據都存儲在分片中,當執行搜索時每個分片獨立搜索後,數據再經過整合返回。那麼,如果要實現分頁查詢該怎麼辦呢?
更多內容參考Elasticsearch資料彙總

按照一般的查詢流程來說,如果我想查詢前10條數據:

  • 1 客戶端請求發給某個節點
  • 2 節點轉發給個個分片,查詢每個分片上的前10條
  • 3 結果返回給節點,整合數據,提取前10條
  • 4 返回給請求客戶端

那麼當我想要查詢第10條到第20條的數據該怎麼辦呢?這個時候就用到分頁查詢了。

from-size"淺"分頁

"淺"分頁的概念是小博主自己定義的,可以理解為簡單意義上的分頁。它的原理很簡單,就是查詢前20條數據,然後截斷前10條,只返回10-20的數據。這樣其實白白浪費了前10條的查詢。

查詢的方法如:

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

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

做過測試,越往後的分頁,執行的效率越低。
通過下圖可以看出,刨去一些異常的數據,總體上還是會隨著from的增加,消耗時間也會增加。而且數據量越大,效果越明顯!

也就是說,分頁的偏移值越大,執行分頁查詢時間就會越長!

scroll“深”分頁

相對於from和size的分頁來說,使用scroll可以模擬一個傳統數據的游標,記錄當前讀取的文檔信息位置。這個分頁的用法,不是為了實時查詢數據,而是為了一次性查詢大量的數據(甚至是全部的數據)。

因為這個scroll相當於維護了一份當前索引段的快照信息,這個快照信息是你執行這個scroll查詢時的快照。在這個查詢後的任何新索引進來的數據,都不會在這個快照中查詢到。但是它相對於from和size,不是查詢所有數據然後剔除不要的部分,而是記錄一個讀取的位置,保證下一次快速繼續讀取。

API使用方法如:

curl -XGET 'localhost:9200/twitter/tweet/_search?scroll=1m' -d '
{
    "query": {
        "match" : {
            "title" : "elasticsearch"
        }
    }
}
'

會自動返回一個_scroll_id,通過這個id可以繼續查詢(實際上這個ID會很長哦!):

curl -XGET  'localhost:9200/_search/scroll?scroll=1m&scroll_id=c2Nhbjs2OzM0NDg1ODpzRlBLc0FXNlNyNm5JWUc1'

註意,我在使用1.4版本的ES時,只支持把參數放在URL路徑裡面,不支持在JSON body中使用。

有個很有意思的事情,細心的會發現,這個ID其實是通過base64編碼的:

cXVlcnlUaGVuRmV0Y2g7MTY7MjI3NTp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzIyNzQ6dnRYS0o4bG5RSW1kaXdjRHRQVC1rQTsyMjgwOnZ0WEtKOGxuUUltZGl3Y0R0UFQta0E7MjI4MTp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzIyODM6dnRYS0o4bG5RSW1kaXdjRHRQVC1rQTsyMjgyOnZ0WEtKOGxuUUltZGl3Y0R0UFQta0E7MjI4Njp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzIyODc6dnRYS0o4bG5RSW1kaXdjRHRQVC1rQTsyMjg5OnZ0WEtKOGxuUUltZGl3Y0R0UFQta0E7MjI4NDp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzIyODU6dnRYS0o4bG5RSW1kaXdjRHRQVC1rQTsyMjg4OnZ0WEtKOGxuUUltZGl3Y0R0UFQta0E7MjI3Njp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzIyNzc6dnRYS0o4bG5RSW1kaXdjRHRQVC1rQTsyMjc4OnZ0WEtKOGxuUUltZGl3Y0R0UFQta0E7MjI3OTp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzA7

如果使用解碼工具可以看到:

queryThenFetch;16;2275:vtXKJ8lnQImdiwcDtPT-kA;2274:vtXKJ8lnQImdiwcDtPT-kA;2280:vtXKJ8lnQImdiwcDtPT-kA;2281:vtXKJ8lnQImdiwcDtPT-kA;2283:vtXKJ8lnQImdiwcDtPT-kA;2282:vtXKJ8lnQImdiwcDtPT-kA;2286:vtXKJ8lnQImdiwcDtPT-kA;2287:vtXKJ8lnQImdiwcDtPT-kA;2289:vtXKJ8lnQImdiwcDtPT-kA;2284:vtXKJ8lnQImdiwcDtPT-kA;2285:vtXKJ8lnQImdiwcDtPT-kA;2288:vtXKJ8lnQImdiwcDtPT-kA;2276:vtXKJ8lnQImdiwcDtPT-kA;2277:vtXKJ8lnQImdiwcDtPT-kA;2278:vtXKJ8lnQImdiwcDtPT-kA;2279:vtXKJ8lnQImdiwcDtPT-kA;0;

雖然搞不清楚裡面是什麼內容,但是看到了一堆規則的鍵值對,總是讓人興奮一下!

測試from&size VS scroll的性能

首先呢,需要在java中引入elasticsearch-jar,比如使用maven:

<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>1.4.4</version>
</dependency>

然後初始化一個client對象:

private static TransportClient client;
    private static String INDEX = "index_name";
    private static String TYPE = "type_name";
    
    public static TransportClient init(){
        Settings settings = ImmutableSettings.settingsBuilder()
                 .put("client.transport.sniff", true)
                 .put("cluster.name", "cluster_name")
                 .build();
        client = new TransportClient(settings).addTransportAddress(new InetSocketTransportAddress("localhost",9300));
        return client;
    }
    public static void main(String[] args) {
        TransportClient client = init();
        //這樣就可以使用client執行查詢了
    }

然後就是創建兩個查詢過程了 ,下麵是from-size分頁的執行代碼:

System.out.println("from size 模式啟動!");
Date begin = new Date();
long count = client.prepareCount(INDEX).setTypes(TYPE).execute().actionGet().getCount();
SearchRequestBuilder requestBuilder = client.prepareSearch(INDEX).setTypes(TYPE).setQuery(QueryBuilders.matchAllQuery());
for(int i=0,sum=0; sum<count; i++){
    SearchResponse response = requestBuilder.setFrom(i).setSize(50000).execute().actionGet();
    sum += response.getHits().hits().length;
    System.out.println("總量"+count+" 已經查到"+sum);
}
Date end = new Date();
System.out.println("耗時: "+(end.getTime()-begin.getTime()));

下麵是scroll分頁的執行代碼,註意啊!scroll裡面的size是相對於每個分片來說的,所以實際返回的數量是:分片的數量*size

System.out.println("scroll 模式啟動!");
begin = new Date();
SearchResponse scrollResponse = client.prepareSearch(INDEX)
    .setSearchType(SearchType.SCAN).setSize(10000).setScroll(TimeValue.timeValueMinutes(1)) 
    .execute().actionGet();  
count = scrollResponse.getHits().getTotalHits();//第一次不返回數據
for(int i=0,sum=0; sum<count; i++){
    scrollResponse = client.prepareSearchScroll(scrollResponse.getScrollId())  
        .setScroll(TimeValue.timeValueMinutes(8))  
    .execute().actionGet();
    sum += scrollResponse.getHits().hits().length;
    System.out.println("總量"+count+" 已經查到"+sum);
}
end = new Date();
System.out.println("耗時: "+(end.getTime()-begin.getTime()));

我這裡總的數據有33萬多,分別以每頁5000,10000,50000的數據量請求,得到如下的執行時間:

可以看到僅僅30萬,就相差接近一倍的性能,更何況是如今的大數據環境...因此,如果想要對全量數據進行操作,快換掉fromsize,使用scroll吧!

參考

1 簡書:elasticsearch 的滾動(scroll)
2 16php:Elasticsearch Scroll API詳解
3 elastic:from-size查詢
4 elastic:scroll query


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 首先要將#include <atlimage.h>加進來,開始時我加到stdafx.h中,但一直提示windows.h被重覆引入的問題,後將其加在別的頭文件中,就可以了.. --! 一、圖片的載入 如果需要在界面上顯示的是已經存在的圖片,那麼需要將待顯示的圖片載入至CImage對象之中,CImage
  • PHP的預設機制:每一次php請求,會有1/100的概率(預設值)觸發“session回收”。如果“session回收”發生,那就會檢查/tmp/sess_*的文件,如果最後的修改時間到現在超過了1440秒(gc_maxlifetime的值),就將其刪除,意味著這些session過期失效 文件一般為
  • java oop 1.面向過程的結構化程式設計弊端:方法和數據結構都是毫無規律的定義在程式中任何位置 方法定義和方法要處理的數據結構也都是分開定義2.對象:每new一次,就創建1個新對象,和原來的對象之間沒有影響3.需求中的名詞:對象 動詞:方法4.方法簽名:包含方法名和參數類型類表“順序”, 重載
  • 字元串表示的「true」轉換為布爾型的「true」
  • 在軟體系統中,I/O的速度要比記憶體的速度慢很多,因此I/O經常會稱為系統的瓶頸。所有,提高I/O速度,對於提升系統的整體性能有很大的作用。 在java標準的I/O中,是基於流的I/O的實現,即InputStream和OutPutStream,這種基於流的實現以位元組為基本單元,很容易實現各種過濾器。
  • & 160;& 160;& 160;& 160; "上一篇隨筆" 介紹了Gradle的安裝與任務管理,這篇著重介紹Gradle的內建任務(in built tasks)與自定義任務(custom tasks),藉助Gradle提供的眾多內建任務類型以及自己定製的任務類型,Java Web、Andro
  • 這是在前一個例子的基礎上,利用springMVC,整合了一下mybits,通過查詢mysql資料庫得到結果然後展示給前臺的一個簡單的網站demo。
  • Swift是蘋果2014年推出的全新的編程語言,它繼承了C語言、ObjC的特性,且剋服了C語言的相容性問題。Swift發展過程中不僅保留了ObjC很多語法特性,它也借鑒了多種現代化語言的特點,在其中你可以看到C#、Java、Javascript、Python等多種語言的影子。同時在2015年的WWD
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...