1. 程式人生 > >es 分頁兩種方法

es 分頁兩種方法

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吧!

相關推薦

es 方法

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

場景

通過頁碼分頁:1-1. 入參: page -- 當前頁 pagesize -- 每頁顯示條數 1-2. 出參: itemcount -- 總條數 pagecount -- 總頁數 list -- 資料列表 通過id分頁:2-1. 入參: id -- 查詢id,0代表第一頁 pagesize -- 每

mongoDB方法

mongoDB的分頁查詢是通過limit(),skip(),sort()這三個函式組合進行分頁查詢的 下面這個是我的測試資料 db.test.find().sort({"age":1}); 第一種方法 查詢第一頁的資料:db.test.find().sor

淺談方法實現瀏覽器內多個標簽之間的通信

tools view -s data- oca microsoft oar art set 調用localstorge、cookies等本地存儲方式。 方法一: localstorge在一個標簽頁裏被添加、修改或刪除時,都會觸發一個storage事件,通過在另一個標簽頁裏監

Pagehelper 不情況的解決方法

第一種情況: mybatis 引入版本不對 <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-sp

頁面可返回到前一離開時的瀏覽位置方法

方法一:簡單粗暴返回前一頁  1 <a id="aa">News & Events</a> 2 3 4 <script> 5 $("#aa").click(function(){ 6 history.go(-1) 7 }) 8 <

【 MATLAB 】使用 MATLAB 求由差方程表示的濾波器的響應的方法

例題: 一個3階低通濾波器由下面差分方程描述: y(n) = 0.0181 x(n) + 0.0543 x(n-1) + 0.0543 x(n-2) + 0.0181 x(n-3) + 1.76 y(n-1) - 1.1829 y(n-2) + 0.2781 y(n-3)

方法讓WordPress只在首顯示友情連結

  對於每個網站的友情連結都是非常重要的因素,一個優秀的外鏈可以為自己的網站帶來非常穩定的流量,有助於我們網站的飛速發展!但是友情連結的設定也是有技巧的,如果按照預設的設定友情連結的話,wp的友情連結是全站顯示而對方的部落格友情連結只顯示在主頁,如此相當於你給對方做了一個全

PAT (Basic Level) Practice (中文) 1037 在霍格沃茨找零錢 (20 )(C++)(方法

1037 在霍格沃茨找零錢 (20 分) 如果你是哈利·波特迷,你會知道魔法世界有它自己的貨幣系統 —— 就如海格告訴哈利的:“十七個銀西可(Sickle)兌一個加隆(Galleon),二十九個納特(Knut)兌一個西可,很容易。”現在,給定哈利應付的價錢 P 和他實付的錢 A,你的

Python獲取當前檔名方法:__file__、sys.argv[0]

Python獲取當前檔名可以通過__file__或者sys.argv[0],下面以test.py檔案為例. test.py: # -*- coding: utf-8 -*- # test.py import sys import os # 絕對路徑 print(__fi

PAT (Advanced Level) Practice 1027 Colors in Mars (20 )(C++)(甲級)(方法

1027 Colors in Mars (20 分) People in Mars represent the colors in their computers in a similar way as the Earth people. That is, a color is re

CCF201712-1 最小差值(100)python方法實現

最小差值 問題描述 問題描述    給定n個數,請找出其中相差(差的絕對值)最小的兩個數,輸出它們的差值的絕對值。 輸入格式    輸入第一行包含一個整數n。    第二行包含n個正整數,相鄰整數之間使用一個空格分隔。 輸出格式    輸出一個整數,表示答案。 樣例輸入 

js呼叫列印當前方法

方法一:<%@ page language="java" import="java.util.*" pageEncoding="GBK"%> <%@ page contentType="text/html; charset=GBK"%> <%@

linux下終端屏使用的方法(screen和tmux)

本文主要介紹兩種終端分屏工具:screen和tmux,分享出來供大家參考學習,下面來看看詳細的介紹: 一、使用screen分屏(只能上下分屏,不能左右分屏) (1)安裝工具 在ubuntu系統中使用sudo apt-get install screen 安裝s

【Jquery】jQuery獲取URL參數的方法

ont ras mil scrip line 兩種方法 lower quest request jQuery獲取URL參數的關鍵是獲取到URL,然後對URL進行過濾處理,取出參數。 location.href是取得URL。location.search是取得URL“?

線程的啟動的方法,Runnable接口,run()的調用

ride 之前 線程終止 源碼解析 star 有意 tro thread類 override 實現並啟動線程有兩種方法1、寫一個類繼承自Thread類,重寫run方法。用start方法啟動線程2、寫一個類實現Runnable接口,實現run方法。用new Thread(Ru

spring 讀取properties的方法

jdbc factor frame ram con framework html tex 讀取 一:直接使用context命名空間 如: <beans xmlns="http://www.springframework.org/schema/beans" xm

Parallels Desktop 12卸載的方法

對於mac系統虛擬機:Parallels Desktop 12怎麽卸載呢? 首先在Mac電腦中打開應用程序,然後找到Parallels Desktop 12軟件圖標,將它移除至廢紙簍中就可以了。如果我們已經在虛擬機中安裝了Windows,就需要先將這些Windows刪除,這樣才不會占用內存。

js數組去重的方法

遍歷 方法 doc 思路 i++ 代碼 數組去重 -- length 數組去重這種問題經常會遇到,解決方法也有很多,這裏就總結兩種比較常用的方法。 方法一 第一種方法的思路:遍歷數組裏的元素,由第一個元素開始依次按照順序與其後面的元素相比較,如果不同則不

使用Python生成源文件的方法

mob zhang mod pri tid 串接 數字 能夠 package 利用Python的字符串處理模塊,開發者能夠編寫腳本用來生成那些格式同樣的C、C++、JAVA源程序、頭文件和測試文件,從而避免大量的反復工作。本文概述兩種利用Python string類生成