Elasticsearch Java API 搜索之Scrolls(四)

Using scrolls in Java

首先需要阅读 [scroll documentation](https://www.elastic.co/guide/en/elasticsearch/reference/5.6/search-request-scroll.html)

一般搜索请求都是返回一"页"数据,无论数据量多大都一起返回给用户,Scroll API可以允许我们检索大量数据(甚至全部数据)。Scroll API允许我们做一个初始阶段搜索并且持续批量从Elasticsearch里拉取结果直到没有结果剩下。这有点像传统数据库里的cursors(游标)。 Scroll API的创建并不是为了实时的用户响应,而是为了处理大量的数据(Scrolling is not intended for real time user requests, but rather for processing large amounts of data)。从 scroll 请求返回的结果只是反映了 search 发生那一时刻的索引状态,就像一个快照(The results that are returned from a scroll request reflect the state of the index at the time that the initial search request was made, like a snapshot in time)。后续的对文档的改动(索引、更新或者删除)都只会影响后面的搜索请求。

import static org.elasticsearch.index.query.QueryBuilders.*;
QueryBuilder qb = termQuery("multi", "test");

SearchResponse scrollResp = client.prepareSearch(test)
        .addSort(FieldSortBuilder.DOC_FIELD_NAME, SortOrder.ASC)
        .setScroll(new TimeValue(60000)) //为了使用 scroll,初始搜索请求应该在查询中指定 scroll 参数,告诉 Elasticsearch 需要保持搜索的上下文环境多长时间(滚动时间)
        .setQuery(qb)
        .setSize(100).get(); //max of 100 hits will be returned for each scroll
//Scroll until no hits are returned
do {
    for (SearchHit hit : scrollResp.getHits().getHits()) {
        //Handle the hit...
    }

    scrollResp = client.prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(60000)).execute().actionGet();
} while(scrollResp.getHits().getHits().length != 0); // Zero hits mark the end of the scroll and the while loop.

如果超过滚动时间,继续使用该滚动ID搜索数据,则会报错:

Caused by: SearchContextMissingException[No search context found for id [2861]]
    at org.elasticsearch.search.SearchService.findContext(SearchService.java:613)
    at org.elasticsearch.search.SearchService.executeQueryPhase(SearchService.java:403)
    at org.elasticsearch.search.action.SearchServiceTransportAction$SearchQueryScrollTransportHandler.messageReceived(SearchServiceTransportAction.java:384)
    at org.elasticsearch.search.action.SearchServiceTransportAction$SearchQueryScrollTransportHandler.messageReceived(SearchServiceTransportAction.java:381)
    at org.elasticsearch.transport.TransportRequestHandler.messageReceived(TransportRequestHandler.java:33)
    at org.elasticsearch.transport.RequestHandlerRegistry.processMessageReceived(RequestHandlerRegistry.java:75)
    at org.elasticsearch.transport.TransportService$4.doRun(TransportService.java:376)
    at org.elasticsearch.common.util.concurrent.AbstractRunnable.run(AbstractRunnable.java:37)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

虽然当滚动有效时间已过,搜索上下文(Search Context)会自动被清除,但是一值保持滚动代价也是很大的,所以当我们不在使用滚动时要尽快使用Clear-Scroll API进行清除。

清除Scroll

/**
     * 清除滚动ID
     * @param client
     * @param scrollIdList
     * @return
     */
    public static boolean clearScroll(Client client, List<String> scrollIdList){
        ClearScrollRequestBuilder clearScrollRequestBuilder = client.prepareClearScroll();
        clearScrollRequestBuilder.setScrollIds(scrollIdList);
        ClearScrollResponse response = clearScrollRequestBuilder.get();
        return response.isSucceeded();
    }
    /**
     * 清除滚动ID
     * @param client
     * @param scrollId
     * @return
     */
    public static boolean clearScroll(Client client, String scrollId){
        ClearScrollRequestBuilder clearScrollRequestBuilder = client.prepareClearScroll();
        clearScrollRequestBuilder.addScrollId(scrollId);
        ClearScrollResponse response = clearScrollRequestBuilder.get();
        return response.isSucceeded();
    }

实例

public class ScrollsAPI extends ElasticsearchClientBase {

    private String scrollId;

    @Test
    public void testScrolls() throws Exception {

        SearchResponse scrollResp = client.prepareSearch("twitter")
                .addSort(FieldSortBuilder.DOC_FIELD_NAME, SortOrder.ASC)
                .setScroll(new TimeValue(60000)) //为了使用 scroll,初始搜索请求应该在查询中指定 scroll 参数,告诉 Elasticsearch 需要保持搜索的上下文环境多长时间(滚动时间)
                .setQuery(QueryBuilders.termQuery("user", "kimchy"))                 // Query 查询条件
                .setSize(5).get(); //max of 100 hits will be returned for each scroll
        //Scroll until no hits are returned

        scrollId = scrollResp.getScrollId();
        do {
            for (SearchHit hit : scrollResp.getHits().getHits()) {
                //Handle the hit...

                System.out.println("" + hit.getSource().toString());
            }

            scrollResp = client.prepareSearchScroll(scrollId).setScroll(new TimeValue(60000)).execute().actionGet();
        }
        while (scrollResp.getHits().getHits().length != 0); // Zero hits mark the end of the scroll and the while loop.
    }

    @Override
    public void tearDown() throws Exception {
        ClearScrollRequestBuilder clearScrollRequestBuilder = client.prepareClearScroll();
        clearScrollRequestBuilder.addScrollId(scrollId);
        ClearScrollResponse response = clearScrollRequestBuilder.get();

        if (response.isSucceeded()) {
            System.out.println("成功清除");
        }

        super.tearDown();
    }
}
  • [ScrollsAPI.java](https://gitee.com/quanke/elasticsearch-java-study/blob/master/src/test/java/name/quanke/es/study/search/ScrollsAPI.java)
  • [本手册完整实例](https://gitee.com/quanke/elasticsearch-java-study)

原文发布于微信公众号 - 全栈架构(keatingr)

原文发表时间:2017-12-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏FreeBuf

远程RPC溢出EXP编写实战之MS06-040

0x01 前言 MS06-040算是个比较老的洞了,在当年影响十分之广,基本上Microsoft大部分操作系统都受到了影响,威力不亚于17年爆出的”永恒之蓝”漏...

28310
来自专栏c#开发者

BizTalk 2006 R2 如何实现EDI报文的接收处理

BizTalk 2006 R2 如何实现EDI报文的接收处理 本专题介绍使用标准的EDI ANSI x1报文,实现通过BizTalk接收一个810(Invoi...

3378
来自专栏恰同学骚年

.NET Core微服务之基于IdentityServer建立授权与验证服务(续)

上一篇我们基于IdentityServer4建立了一个AuthorizationServer,并且继承了QuickStartUI,能够成功获取Token了。这一...

2485
来自专栏乐沙弥的世界

mongoDB 文档更新

1、mongoDB文档更新有很多个不同的方法,传统的update,以及3.2版本之后的updateOne,updateMany 2、mongoDB文档替换也...

1722
来自专栏DeveWork

Mac OS X巧用AppleScript 制作网络位置切换自动化脚本(自动配置PAC 文件)

事情是这样的,自带的Macbook Air 在实习单位入的是办公网,办公网走自动代理(需要配置PAC 文件)。同时回来宿舍或家里需要民用的宽带网络。切换的时候出...

4885
来自专栏伪君子的梦呓

网络安全实验室(基础关) writeup~上

因为参加了一个比赛(网鼎杯),所以要快速入门一下信息安全,没想到赛制是线上采用 CTF 的赛制,所以就找了点题目做了一下。

3992
来自专栏IMWeb前端团队

Node.js ORM 框架 sequelize 实践

本文作者:IMWeb zzbozheng 原文出处:IMWeb社区 未经同意,禁止转载 Node.js ORM 框架 sequelize 实践 最近在...

56810
来自专栏JackeyGao的博客

Django小技巧20: 使用多个settings模块

通常来说, 为了保持项目的配置简单,我们会避免使用多个配置文件。但理想很丰满, 现实是随着项目越来越大, settings.py可能也会变得相当复杂. 在那种情...

4161
来自专栏Jerry的SAP技术分享

通过一个实际例子理解Kubernetes里pod的自动scale - 水平自动伸缩

kubectl scale命令用于程序在负载加重或缩小时进行pod扩容或缩小,我们通过一些实际例子来观察scale命令到底能达到什么效果。

1373
来自专栏刘君君

使用Spring Event解耦业务开发

Spring 事件是观察者模式的一种体现,对象间的一对多关系,被观察者发出信号时候会通知监听该事件的观察者;而发布-订阅模型往往需要一个调度中心,如消息队列等

1862

扫码关注云+社区

领取腾讯云代金券