Elasticsearch滚动查询(java)

这里写自定义目录标题

欢迎使用Markdown编辑器

使用

新的改变

import com.google.common.collect.ImmutableMap;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.search.ClearScrollRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchScrollRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.Scroll;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 *
 */
@Api("es滚动查询demo")
@RestController
@RequestMapping("/test")
@Slf4j
public class TestScroll {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    /**
     * 滚动查询
     * <p>
     * 第二次滚动要携带scrollId
     *
     * @return Map 结果,结构:↓
     * {
     * "total": 123,
     * "list": [ {},{}  ],
     * "scrollId": "qqqqqqqqqqqqqqqqqqqqqqqqqq"
     * }
     */
    @ApiOperation("查询数据")
    @GetMapping
    public Map getScroll(@RequestParam(required = false) @ApiParam("滚动id,第一次滚动不需要传") String scrollId, @RequestParam(required = false, defaultValue = "10") @ApiParam("滚动大小") int size, @RequestParam(required = false) @ApiParam("查询条件1") String param) {
        final String index = "index*";

        //检索条件
        QueryBuilder queryBuilder = param == null ? null : QueryBuilders.termsQuery("param", param);

        SearchResponse searchResponse = null;
        //scrollId为空表示第一次滚动
        if (StringUtils.isBlank(scrollId)) {
            //第一次滚动保持时间
            final long fristKeepMinutes = 2;
            searchResponse = firstScroll(index, queryBuilder, null, size, fristKeepMinutes);
        } else {
            final long scrollKeepMinutes = 1;
            searchResponse = manyTimesScroll(scrollId, scrollKeepMinutes);
        }
        return ElasticsearchResponseResultBuilder(searchResponse);
    }

    /**
     * 第一次滚动
     *
     * @param index        索引(可以使用通配符)
     * @param queryBuilder 查询条件
     * @param size         滚动页大小
     * @param keepAlive    滚动保持时间,单位:分钟
     **/
    private SearchResponse firstScroll(String index, QueryBuilder queryBuilder, FieldSortBuilder order, int size, long keepAlive) {

        SearchRequest searchRequest = new SearchRequest(index);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.size(size);
        if (queryBuilder != null) searchSourceBuilder.query(queryBuilder);
        if (order != null) searchSourceBuilder.sort(order);
        searchRequest.source(searchSourceBuilder);

        Scroll scroll = new Scroll(TimeValue.timeValueMinutes(keepAlive));
        searchRequest.scroll(scroll);
        SearchResponse response = null;
        try {
            response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return response;
    }

    /**
     * 第二次+ 滚动
     *
     * @param scrollId  滚动id。es根据此id继续滚动
     * @param keepAlive 更新滚动时间,单位:分钟
     */
    private SearchResponse manyTimesScroll(String scrollId, long keepAlive) {
        SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);
        scrollRequest.scroll(TimeValue.timeValueMinutes(keepAlive));
        SearchResponse response = null;
        try {
            //根据上次的滚动参数继续滚动查询,不需要重新设置
            response = restHighLevelClient.scroll(scrollRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return response;
    }

    /**
     * 结果封装
     */
    private Map ElasticsearchResponseResultBuilder(SearchResponse response) {
        if (response == null) {
            return null;
        }
        SearchHit[] hits = response.getHits().getHits();
        List resultList = new ArrayList(hits.length);
        for (SearchHit hit : hits) {
            resultList.add(hit.getSourceAsMap());
        }
        return ImmutableMap.of(
                "total", response.getHits().getTotalHits().value,
                "list", resultList,
                "scrollId", response.getScrollId()
        );
    }

    @ApiOperation(value = "清理滚动", notes = "个人认为同一个滚动scrollId发生改变,旧的scrollId可能已经失效了,不需要清理")
    @DeleteMapping
    public void clear(String scrollId) {
        //清理scroll,释放资源
        ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
        clearScrollRequest.addScrollId(scrollId);
        try {
            restHighLevelClient.clearScroll(clearScrollRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error("清理滚动异常,scrollId{}", scrollId);
            e.printStackTrace();
        }
    }
}
Elasticsearch滚动索引可以用来遍历大量数据,而不会导致内存溢出或超时。下面是Java代码实现滚动索引的步骤: 1.创建Elasticsearch客户端: ``` TransportClient client = new PreBuiltTransportClient(Settings.EMPTY) .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300)); ``` 2.定义搜索条件: ``` SearchRequestBuilder searchRequestBuilder = client.prepareSearch("indexName") .setTypes("typeName") .setQuery(QueryBuilders.matchAllQuery()) .setSize(100) .setScroll(new TimeValue(60000)); ``` 这里设置了每次搜索返回100条记录,并且每次搜索的有效时间为60秒。 3.执行搜索: ``` SearchResponse searchResponse = searchRequestBuilder.execute().actionGet(); ``` 4.处理搜索结果: ``` while (true) { for (SearchHit searchHit : searchResponse.getHits().getHits()) { // 处理每个搜索结果 } searchResponse = client.prepareSearchScroll(searchResponse.getScrollId()) .setScroll(new TimeValue(60000)).execute().actionGet(); if (searchResponse.getHits().getHits().length == 0) { break; } } ``` 通过循环,我们可以遍历所有搜索结果。在每次循环结束后,我们需要使用`prepareSearchScroll`方法获取下一页搜索结果,直到没有更多结果为止。 5.关闭客户端: ``` client.close(); ``` 完整的Java代码示例: ``` TransportClient client = new PreBuiltTransportClient(Settings.EMPTY) .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300)); SearchRequestBuilder searchRequestBuilder = client.prepareSearch("indexName") .setTypes("typeName") .setQuery(QueryBuilders.matchAllQuery()) .setSize(100) .setScroll(new TimeValue(60000)); SearchResponse searchResponse = searchRequestBuilder.execute().actionGet(); while (true) { for (SearchHit searchHit : searchResponse.getHits().getHits()) { // 处理每个搜索结果 } searchResponse = client.prepareSearchScroll(searchResponse.getScrollId()) .setScroll(new TimeValue(60000)).execute().actionGet(); if (searchResponse.getHits().getHits().length == 0) { break; } } client.close(); ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值