es之java分頁操作


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

· 1 客戶端請求發給某個節點

· 2 節點轉發給個個分片,查詢每個分片上的前10條

· 3 結果返回給節點,整合數據,提取前10條

· 4 返回給請求客戶端

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

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

構造數據:

/**插入一百條數據*/
@Test
// 批量查詢100條記錄
public void createDocument100() throws Exception {
   for(int i=1;i<=100;i++){
       XContentBuilder builder = null;
       try {
           builder = jsonBuilder()
                  .startObject()
                  .field("title", "第"+i+"本書")
                  .field("author", "作者"+i)
                  .field("id" , i)
                  .field("message", i+"是英國物理學家斯蒂芬·霍金創作的科學著作,首次出版於1988年。全書共十二章,講的全都是關於宇宙本性的最前沿知識,包括:我們的宇宙圖像、空間和時間、膨脹的宇宙、不確定性原理、黑洞、宇宙的起源和命運等內容,深入淺出地介紹了遙遠星系、黑洞、粒子、反物質等知識")
                  .endObject();
           String json = builder.string();
           IndexResponse response = this.client.prepareIndex("blog2", "article")
                  .setSource(json, XContentType.JSON)
                  .get();
           // 索引名稱
           String _index = response.getIndex();
           // 類型
           String _type = response.getType();
           // 文檔ID
           String _id = response.getId();
           // 版本
           long _version = response.getVersion();
           // 返回的操作狀態
           RestStatus status = response.status();
           System.out.println("索引名稱:"+_index+" "+"類型 :" +  _type + " 文檔ID:"+_id+" 版本 :"+_version+" 返回的操作狀態:"+status);

      } catch (IOException e) {
           e.printStackTrace();
      }
  }
}

1.9.1:淺分頁

/**
* 查詢所有的方法
searchRequestBuilder 的 setFrom【從0開始】 和 setSize【查詢多少條記錄】方法實現
* */
@Test
public void sortPages(){
   // 搜索數據
   // get() === execute().actionGet()
   SearchRequestBuilder searchRequestBuilder = transportClient.prepareSearch("blog2").setTypes("article")
          .setQuery(QueryBuilders.matchAllQuery());//默認每頁10條記錄
   final long totalHits = searchRequestBuilder.get().getHits().getTotalHits();//總條數
   final int pageDocument = 10 ;//每頁顯示多少條
   final long totalPage = totalHits / pageDocument;//總共分多少頁
   for(int i=1;i<=totalPage;i++){
       System.out.println("=====================當前打印的是第 :"+i+" 頁==============");
       //setFrom():從第幾條開始檢索,默認是0。
       //setSize():查詢多少條文檔。
       searchRequestBuilder.setFrom(i*pageDocument).setSize(pageDocument);

       SearchResponse searchResponse = searchRequestBuilder.get();
       SearchHits hits = searchResponse.getHits();
       Iterator<SearchHit> iterator = hits.iterator();
       while (iterator.hasNext()) {
           SearchHit searchHit = iterator.next(); // 每個查詢對象
           System.out.println(searchHit.getSourceAsString()); // 獲取字符串格式打印
      }
  }
}

1.9.2:分頁優化-深分頁(scroll)

對於上面介紹的淺分頁,當Elasticsearch響應請求時,它必須確定docs的順序,排列響應結果。

如果請求的頁數較少(假設每頁20個docs), Elasticsearch不會有什么問題,但是如果頁數較大時,比如請求第20頁,Elasticsearch不得不取出第1頁到第20頁的所有docs,再去除第1頁到第19頁的docs,得到第20頁的docs。

 

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

 

可以把 scroll 分為初始化和遍歷兩步: 1、初始化時將所有符合搜索條件的搜索結果緩存起來,可以想象成快照; 2、遍歷時,從這個快照里取數據,也就是說,在初始化后對索引插入、刪除、更新數據都不會影響遍歷結果

@Test
public void scrollPages(){
   //獲取Client對象,設置索引名稱,搜索類型(SearchType.SCAN)[5.4移除,對於java代碼,直接返回index順序,不對結果排序],搜索數量,發送請求
   SearchResponse searchResponse = transportClient
      .prepareSearch("blog2")
          .setSearchType(SearchType.DEFAULT)//執行檢索的類別
          .setSize(10).setScroll(new TimeValue(1000)).execute()
          .actionGet();//注意:首次搜索並不包含數據
   //獲取總數量
   long totalCount = searchResponse.getHits().getTotalHits();

   int page=(int)totalCount/(10);//計算總頁數
   System.out.println("總頁數: ================="+page+"=============");
   for (int i = 1; i <= page; i++) {
       System.out.println("=========================頁數:"+i+"====================");

       searchResponse = transportClient
              .prepareSearchScroll(searchResponse.getScrollId())//再次發送請求,並使用上次搜索結果的ScrollId
              .setScroll(new TimeValue(1000)).execute()
              .actionGet();
       SearchHits hits = searchResponse.getHits();
       for (SearchHit searchHit : hits) {

           System.out.println(searchHit.getSourceAsString()); // 獲取字符串格式打印
      }

  }
}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM