一、引入依赖

<!--SpringBoot集成Es的包-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

引入之后打开右边的 maven按钮查看RestHighLevelClient版本是否和自己的es版本一致,如果不一直 需要手动设置依赖版本,覆盖spring自带的版本

<properties>
    <java.version>1.8</java.version>
    <!--覆盖 elasticsearch-rest-high-level-client 的版本-->
    <elasticsearch.version>7.8.1</elasticsearch.version>
</properties>

pom依赖.jpg


二、编写配置类(RestHighLevelClient)

/**
 * @Author zyf
 * @Date 2021/7/31 16:06
 * @Version 1.0
 */
@Configuration
@AllArgsConstructor
@Data
public class RestHighLevelClientConfig {
    
    // 将方法的返回结果交给spring管理
    @Bean
    public RestHighLevelClient restHighLevelClient(){
        // 主机ip和端口号以及协议
        HttpHost host = new HttpHost("xxx.xxx.xxx.xxx", 9200, HttpHost.DEFAULT_SCHEME_NAME);
        RestClientBuilder builder = RestClient.builder(host);

        //密码
        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("elastic", "xxxxxxx"));

        builder.setHttpClientConfigCallback(f -> f.setDefaultCredentialsProvider(credentialsProvider));

        RestHighLevelClient restHighLevelClient = new RestHighLevelClient(builder );
        return restHighLevelClient;
    }
}

三、索引操作

首先要注入刚刚配置好的RestHighLevelClient对象

@Autowired
private RestHighLevelClient restHighLevelClient;

1、简单索引的创建

//创建索引(不带mapping,ElasticSearch默认会根据你的添加的文档来创建mapping)
@GetMapping("/createIndex/{index}")
public R<?> createIndex(@PathVariable("index") String index) throws IOException {

    // 创建索引的请求
    CreateIndexRequest request = new CreateIndexRequest(index);

    // 执行请求
    CreateIndexResponse response = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
    return R.ok(response);
}

2、创建索引时设置mapping

//创建索引时设置mapping
@GetMapping("/createMappingIndex/{index}")
public R<?> createMappingIndex(@PathVariable("index") String index) throws IOException {

    // 创建索引的请求
    CreateIndexRequest request = new CreateIndexRequest(index);

    // mapping规则去别的地方写好之后,复制粘贴过来,IDEA会自动转义相关符号
    String mapping = "{\n" +
        "        \"properties\": {\n" +
        "            \"id\": {\n" +
        "                \"type\": \"keyword\"\n" +
        "            },\n" +
        "            \"title\": {\n" +
        "                \"type\": \"keyword\"\n" +
        "            },\n" +
        "            \"md_content\": {\n" +
        "                \"type\": \"text\"\n" +
        "            },\n" +
        "            \"html_content\": {\n" +
        "                \"type\": \"text\"\n" +
        "            },\n" +
        "            \"summary\": {\n" +
        "                \"type\": \"text\",\n" +
        "                \"fields\": {\n" +
        "                    \"keyword\": {\n" +
        "                        \"type\": \"keyword\",\n" +
        "                        \"ignore_above\": 256\n" +
        "                    }\n" +
        "                }\n" +
        "            },\n" +
        "            \"view_count\": {\n" +
        "                \"type\": \"integer\"\n" +
        "            },\n" +
        "            \"status\": {\n" +
        "                \"type\": \"integer\"\n" +
        "            },\n" +
        "            \"is_top\": {\n" +
        "                \"type\": \"integer\"\n" +
        "            },\n" +
        "            \"category_id\": {\n" +
        "                \"type\": \"keyword\"\n" +
        "            },\n" +
        "            \"sort\": {\n" +
        "                \"type\": \"integer\"\n" +
        "            },\n" +
        "            \"publish_date\": {\n" +
        "                \"type\": \"date\",\n" +
        "                \"format\": \"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis\"\n" +
        "            },\n" +
        "            \"create_by\": {\n" +
        "                \"type\": \"keyword\"\n" +
        "            },\n" +
        "            \"create_time\": {\n" +
        "                \"type\": \"date\", \n" +
        "                \"format\": \"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis\"\n" +
        "            },\n" +
        "            \"update_by\": {\n" +
        "                \"type\": \"keyword\"\n" +
        "            },\n" +
        "            \"update_time\": {\n" +
        "                \"type\": \"date\",\n" +
        "                \"format\": \"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis\"\n" +
        "            }\n" +
        "        }\n" +
        "    }";

    //添加索引的mapping规则
    request.mapping(mapping, XContentType.JSON);

    // 执行请求
    CreateIndexResponse response = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);

    return R.ok(response);
}

3、索引是否存在

//索引是否存在
@GetMapping("/exitIndex/{index}")
public R<?> exitIndex(@PathVariable("index") String index) throws IOException {

    // 获取索引的请求
    GetIndexRequest request = new GetIndexRequest(index);
    // 执行请求
    boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);

    return R.ok(exists);
}

4、获取索引信息

//获取索引信息
@GetMapping("/getIndex/{index}")
public R<?> getIndex(@PathVariable("index") String index) throws IOException {

    // 获取索引的请求
    GetIndexRequest request = new GetIndexRequest(index);
    // 执行请求
    GetIndexResponse response = restHighLevelClient.indices().get(request, RequestOptions.DEFAULT);
    JSON parse = JSONUtil.parse(response);
    return R.ok(parse);
}

5、设置mapping信息

//设置索引mapping信息
@GetMapping("/setMapping/{index}")
public R<?> setMapping(@PathVariable("index") String index) throws IOException {

    // put mapping的请求
    PutMappingRequest request = new PutMappingRequest(index);

    // mapping规则去别的地方写好之后,复制粘贴过来,IDEA会自动转义相关符号
    String mapping = "{\n" +
        "        \"properties\": {\n" +
        "            \"id\": {\n" +
        "                \"type\": \"keyword\"\n" +
        "            },\n" +
        "            \"title\": {\n" +
        "                \"type\": \"keyword\"\n" +
        "            },\n" +
        "            \"md_content\": {\n" +
        "                \"type\": \"text\"\n" +
        "            },\n" +
        "            \"html_content\": {\n" +
        "                \"type\": \"text\"\n" +
        "            },\n" +
        "            \"summary\": {\n" +
        "                \"type\": \"text\",\n" +
        "                \"fields\": {\n" +
        "                    \"keyword\": {\n" +
        "                        \"type\": \"keyword\",\n" +
        "                        \"ignore_above\": 256\n" +
        "                    }\n" +
        "                }\n" +
        "            },\n" +
        "            \"view_count\": {\n" +
        "                \"type\": \"integer\"\n" +
        "            },\n" +
        "            \"status\": {\n" +
        "                \"type\": \"integer\"\n" +
        "            },\n" +
        "            \"is_top\": {\n" +
        "                \"type\": \"integer\"\n" +
        "            },\n" +
        "            \"category_id\": {\n" +
        "                \"type\": \"keyword\"\n" +
        "            },\n" +
        "            \"sort\": {\n" +
        "                \"type\": \"integer\"\n" +
        "            },\n" +
        "            \"publish_date\": {\n" +
        "                \"type\": \"date\",\n" +
        "                \"format\": \"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis\"\n" +
        "            },\n" +
        "            \"create_by\": {\n" +
        "                \"type\": \"keyword\"\n" +
        "            },\n" +
        "            \"create_time\": {\n" +
        "                \"type\": \"date\", \n" +
        "                \"format\": \"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis\"\n" +
        "            },\n" +
        "            \"update_by\": {\n" +
        "                \"type\": \"keyword\"\n" +
        "            },\n" +
        "            \"update_time\": {\n" +
        "                \"type\": \"date\",\n" +
        "                \"format\": \"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis\"\n" +
        "            }\n" +
        "        }\n" +
        "    }";

    //添加索引的mapping规则
    request.source(mapping, XContentType.JSON);
    // 执行请求
    AcknowledgedResponse response = restHighLevelClient.indices().putMapping(request, RequestOptions.DEFAULT);

    return R.ok(response);
}

6、删除索引

//删除索引
@GetMapping("/deleteIndex/{index}")
public R<?> deleteIndex(@PathVariable("index") String index) throws IOException {

    // 删除索引的请求
    DeleteIndexRequest request = new DeleteIndexRequest(index);

    // 执行删除的请求
    AcknowledgedResponse response = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);

    return R.ok(response);
}

四、文档操作

1、添加文档

//新建文档  id存在就是覆盖文档,不存在是新增文档
@PostMapping("/addDoc/{index}")
public R<?> addDoc(@PathVariable("index") String index, @RequestBody Article article) throws IOException {

    //重复作会全量更新
    IndexRequest request = new IndexRequest(index);

    //设置文档 _id
    request.id("1001");

    // 设置超时时间(默认)
    request.timeout(TimeValue.timeValueSeconds(5));

    // 向请求对象中添加
    request.source(JSONUtil.toJsonStr(article), XContentType.JSON);
    //执行添加请求
    IndexResponse response = restHighLevelClient.index(request, RequestOptions.DEFAULT);

    return R.ok(response);
}

2、更新文档(全局更新/覆盖)

//上面这个添加文档的方法,如果id不存在就是添加,id存在就是更新/(是全局更新,就是说里面的字段全部被覆盖,新对象里没有的字段就没有了)

3、修改文档(局部更新)(推荐)


// 更新文档(局部更新,只会覆盖原文档其中有的字段)
@PostMapping("/updateDoc/{index}")
public R<?> updateDoc(@PathVariable("index") String index, @RequestBody Article article) throws IOException {

    //创建更新请求(指定索引和文档_id)
    UpdateRequest request = new UpdateRequest(index,"1002");

    // 把要更新的数据装进去
    request.doc(JSONUtil.toJsonStr(article),XContentType.JSON);

    // 执行更新语句
    UpdateResponse response = restHighLevelClient.update(request, RequestOptions.DEFAULT);

    return R.ok(response);
}

4、删除文档

// 测试文档删除
@Test
public void testDelDoc() throws IOException {
    DeleteRequest deleteRequest = new DeleteRequest("nan_index","2");
    DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
    System.out.println(deleteResponse);
}

5、根据id查询文档

//获取简单文档数据
@Test
public void testGetDoc() throws IOException {
    GetRequest getRequest = new GetRequest("nan_index");
    getRequest.id("1");
    GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
    System.out.println(getResponse);
}

6、批量添加文档 (批量删除、更新、修改是一样的)

//批量新建文档
@PostMapping("/addDocBatch/{index}")
public R<?> addDocBatch(@PathVariable("index") String index) throws IOException {

    //模拟数据
    List<Article> list = new ArrayList<>();
    for (int i = 0; i < 1000; i++) {
        Article article = new Article();
        article.setId("" + i);
        article.setTitle("测试批量新增标题" + i);
        article.setSummary("测试批量新增Summary" + i);
        list.add(article);
    }

    //创建批量操作请求对象
    BulkRequest bulkRequest = new BulkRequest();

    //将每个新增数据的请求都添加到BulkRequest 中统一请求
    list.forEach(item -> {
        IndexRequest indexRequest = new IndexRequest(index).id(item.getId());
        indexRequest.source(JSONUtil.toJsonStr(item),XContentType.JSON);
        bulkRequest.add(indexRequest);
    });

    // 执行批量请求
    BulkResponse response = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);

    return R.ok(response);
}

7、查询所有(默认只会查询10条数据)

//查询所有
@PostMapping("/findAll/{index}")
public R<?> findAll(@PathVariable("index") String index) throws IOException {

    //全量查询 matchAllQuery
    SearchRequest request = new SearchRequest(index);

    //全量查询 这两行可以省略
    SearchSourceBuilder builder = new SearchSourceBuilder().query(QueryBuilders.matchAllQuery());
    //这里的查询所有默认只会查询10条数据,需要手动指定size
    builder.size(100);
    request.source(builder);

    SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);

    System.out.println(response.getTook());
    SearchHits hits = response.getHits();

    for (SearchHit item : hits) {
        System.out.println(item.getSourceAsString());
    }

    return R.ok(hits);
}

8、分页查询

//分页查询
@PostMapping("/findPage/{index}")
public R<?> findPage(@PathVariable("index") String index, @RequestBody PageQuery query) throws IOException {

    Integer pageNumber = query.getPageNumber();
    Integer pageSize = query.getPageSize();

    //查询请求对象
    SearchRequest request = new SearchRequest(index);

    //全量查询 可以省略
    SearchSourceBuilder builder = new SearchSourceBuilder().query(QueryBuilders.matchAllQuery());
    //分页
    builder.from(pageSize * (pageNumber - 1));// 开始下标(当前页码-1)*每页显示条数
    builder.size(pageSize);// 要查多少个

    // 设置排序规则
    //        builder.sort("id", SortOrder.ASC);

    request.source(builder);

    SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);

    System.out.println(response.getTook());
    SearchHits hits = response.getHits();

    for (SearchHit item : hits) {
        System.out.println(item.getSourceAsString());
    }

    return R.ok(hits);
}

9、条件查询

//条件查询
@PostMapping("/query/{index}")
public R<?> query(@PathVariable("index") String index, @RequestBody PageQuery query) throws IOException {

    Integer pageNumber = query.getPageNumber();
    Integer pageSize = query.getPageSize();

    String title = query.getTitle();

    //查询请求对象
    SearchRequest request = new SearchRequest(index);

    // 构建搜索builder
    SearchSourceBuilder builder = new SearchSourceBuilder();

    //设置条件(精准匹配)
    TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", title);

    builder.query(termQueryBuilder);

    //分页
    builder.from(pageSize * (pageNumber - 1));// 开始下标(当前页码-1)*每页显示条数
    builder.size(pageSize);// 要查多少个

    request.source(builder);

    SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);

    System.out.println(response.getTook());
    SearchHits hits = response.getHits();

    for (SearchHit item : hits) {
        System.out.println(item.getSourceAsString());
    }

    return R.ok(hits);
}

10、范围查询

// 范围查询
@Test
public void testRangeDoc() throws IOException {
    // 构建查询请求
    SearchRequest searchRequest = new SearchRequest("nan_index");

    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    // 设置到范围的字段
    RangeQueryBuilder rangeQueryBuilder = new RangeQueryBuilder("age");
    // 设置范围()gte就是大于等于
    rangeQueryBuilder.gte(24);
    rangeQueryBuilder.lte(30);
    // 把范围查询设置到条件中
    searchSourceBuilder.query(rangeQueryBuilder);
    searchRequest.source(searchSourceBuilder);
    SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    SearchHits hits = searchResponse.getHits();
    for(SearchHit hit :hits){
        System.out.println(hit.getSourceAsString());
    }
}

11、多条件查询(组合查询)

先弄清楚几个api之间的传递关系

api参数层级.png

  • QueryBuilders

封装了一些基础的条件查询

//请求对象
SearchRequest request = new SearchRequest("user");
//相当于请求体对象
SearchSourceBuilder builder = new SearchSourceBuilder();

//设置查询条件
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name","zhangsan");//eq
//RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("age").gt(25).lt(27);//范围

//将查询条件设置到请求体里面
builder.query(termQueryBuilder);
//将请求体设置到请求对象里面
request.source(builder);
//发送请求
SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
  • BoolQueryBuilder

可以将前面的多个查询条件组合起来,和上面的基础查询对象一样,都由QueryBuilders创建出来。

组装好上面的基础查询之后,同样通过SearchSourceBuilder的 .query(查询条件对象) 将这个对象作为参数传进去。

//请求对象
SearchRequest request = new SearchRequest("user");
//相当于请求体对象
SearchSourceBuilder builder = new SearchSourceBuilder();

//创建组合查询对象
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

//must相当于and
boolQueryBuilder.must(QueryBuilders.termQuery("age", 26));
boolQueryBuilder.must(QueryBuilders.termQuery("name", "1"));
boolQueryBuilder.mustNot(QueryBuilders.termQuery("sex", "男"));

//should 相当于 or
boolQueryBuilder.should(QueryBuilders.termQuery("age", 26));
boolQueryBuilder.should(QueryBuilders.termQuery("age", 27));

//范围查询
boolQueryBuilder.filter(QueryBuilders.rangeQuery("age").gt(25).lt(27));


//将组合好的查询条件设置到请求体里面
builder.query(boolQueryBuilder);
//将请求体设置到请求对象里面
request.source(builder);
//发送请求
SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
  • SearchSourceBuilder

相当于请求体对象,上面的查询条件设置好之后,通过该对象的 .query(查询条件对象) 方法,将查询条件放进去,然后将这个对象放进下面的请求对象。

  • SearchRequest

查询文档的请求对象,上面的请求体设置好之后,通过该对象的 .source(SearchSourceBuilder对象) 方法,source对象放进去。

12、字段过滤

// 测试过滤查询出来的字段(也就是当我们不想把表中所有的字段查出来)
@Test
public void testFilterDoc() throws IOException {
    // 构建搜索查询请求
    SearchRequest searchRequest = new SearchRequest().indices("nan_index");

    // 构建查询条件builder
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

    // 构建真正的查询条件(这里是全部查询)
    MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();

    // 把查询条件设置给builder
    searchSourceBuilder.query(matchAllQueryBuilder);

    // 设置过滤字段
    String[] excludes = {};
    String[] includes = {"name"};
    searchSourceBuilder.fetchSource(includes,excludes);

    // 把所有的查询条件builder设置给查询请求
    searchRequest.source(searchSourceBuilder);

    //执行请求
    SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

    //打印结果
    SearchHits hits = searchResponse.getHits();
    for (SearchHit hit:hits) {
        System.out.println(hit.getSourceAsString());
    }
}

13、模糊查询

// 模糊查询
    @Test
    public void testLikeDoc() throws IOException {
        SearchRequest searchRequest = new SearchRequest("nan_index");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        FuzzyQueryBuilder fuzzyQueryBuilder = QueryBuilders.fuzzyQuery("name", "xiao").fuzziness(Fuzziness.TWO);
        searchSourceBuilder.query(fuzzyQueryBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits hits = searchResponse.getHits();
        for(SearchHit hit :hits){
            System.out.println(hit.getSourceAsString());
        }
    }

14、高亮查询

//高亮查询
    @Test
    public void testHighLightDoc() throws IOException {
        // 构建搜索请求
        SearchRequest searchRequest = new SearchRequest("nan_index");

        // 构建搜索条件构造器(也就是总的搜索条件)
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        // 构建单独的一个高亮构建器
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        // 设置高亮字段
        highlightBuilder.preTags("<font color='red'>"); //前缀
        highlightBuilder.postTags("</font>");   // 后缀
        highlightBuilder.field("name");
        // 把单独的高亮构建器设置给总构建器
        searchSourceBuilder.highlighter(highlightBuilder);
        searchSourceBuilder.query(QueryBuilders.matchAllQuery());
        // 把总的搜索条件给到搜索请求中
        searchRequest.source(searchSourceBuilder);
        // 执行请求
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        // 打印结果
        SearchHits hits = searchResponse.getHits();
        for(SearchHit hit :hits){
            System.out.println(hit.getSourceAsString());
            // 获取对应的高亮域
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            System.out.println(highlightFields);
            // 获取对应的高亮字段
            HighlightField highlightField = highlightFields.get("name");
            if(highlightField != null) {
                // 拿到高亮字段的文本域
                Text[] texts = highlightField.getFragments();
                String name = "";
                for (Text text : texts) {
                    name += text;
                    // 打印高亮字段
                    System.out.println(name);
                }
            }
        }
    }

15、聚合查询(最大值、最小值、平均值)

// 最大值、平均值、最小值
@Test
public void testAggraDoc() throws IOException {
    SearchRequest searchRequest = new SearchRequest("nan_index");
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    // 构建一个最大值builder
    MaxAggregationBuilder maxAggregationBuilder = AggregationBuilders.max("MAXAGE").field("age");
    // 把最大值builder设置给总查询条件
    searchSourceBuilder.aggregation(maxAggregationBuilder);

    searchRequest.source(searchSourceBuilder);
    SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    SearchHits hits = searchResponse.getHits();
    for(SearchHit hit : hits){
        System.out.println(hit.getSourceAsString());
    }
}

16、分组查询

// 分组查询
@Test
public void testAggraGroupDoc() throws IOException {
    SearchRequest searchRequest = new SearchRequest("nan_index");
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    // 构建一个分组builder
    // terms里面的参数是给分组取的名字、后面field是要分组的字段
    TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("AGEGROUP").field("age");
    // 把分组builder设置给总查询条件
    searchSourceBuilder.aggregation(termsAggregationBuilder);

    searchRequest.source(searchSourceBuilder);
    SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    SearchHits hits = searchResponse.getHits();
    for(SearchHit hit : hits){
        System.out.println(hit.getSourceAsString());
    }
}

17、滚动查询(Scroll)

//滚动查询
@PostMapping("/queryScroll/{index}")
public R<?> queryScroll(@PathVariable("index") String index){

    //查询请求对象
    SearchRequest request = new SearchRequest(index);

    /*
        初始化scroll
        设定滚动时间间隔
        这个时间并不需要长到可以处理所有的数据,仅仅需要足够长来处理前一批次的结果。每个 scroll 请求(包含 scroll 参数)设置了一个新的失效时间。
    */
    final Scroll scroll = new Scroll(TimeValue.timeValueMinutes(1L));

    //scroll对象放入请求对象
    request.scroll(scroll);

    //开始封装查询条件(这里demo直接查询所有)
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    searchSourceBuilder.query(QueryBuilders.matchAllQuery());

    //设定每次返回多少条数据
    searchSourceBuilder.size(20);

    //请求对象设置完成
    request.source(searchSourceBuilder);

    //发送请求
    SearchResponse response = null;
    try {
        response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
    } catch (IOException e) {
        e.printStackTrace();
    }

    int page = 1;

    SearchHit[] searchHits = response.getHits().getHits();
    System.out.println("-----第"+ page +"页-----");
    //这里是第一页的数据
    for (SearchHit searchHit : searchHits) {
        String sourceAsString = searchHit.getSourceAsString();
        System.out.println(sourceAsString);
    }

    //遍历搜索命中的数据,直到没有数据
    String scrollId = response.getScrollId();//获取当前的scrollId
    while (searchHits != null && searchHits.length > 0) {
        //根据第一次返回的scrollId 创建滚动查询请求对象
        SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);
        scrollRequest.scroll(scroll);

        try {
            //执行滚动查询
            response = restHighLevelClient.scroll(scrollRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }

        //获取每次返回的scrollId
        scrollId = response.getScrollId();

        //获取每次查询的数据
        searchHits = response.getHits().getHits();
        if (searchHits != null && searchHits.length > 0) {
            page++;
            System.out.println("-----第"+ page +"页-----");
            //每次查询的数据
            for (SearchHit searchHit : searchHits) {
                String sourceAsString = searchHit.getSourceAsString();
                System.out.println(sourceAsString);
            }
        }
    }
    
    //清除滚屏
    ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
    clearScrollRequest.addScrollId(scrollId);//也可以选择setScrollIds()将多个scrollId一起使用
    ClearScrollResponse clearScrollResponse = null;
    try {
        clearScrollResponse = restHighLevelClient.clearScroll(clearScrollRequest, RequestOptions.DEFAULT);
    } catch (IOException e) {
        e.printStackTrace();
    }
    boolean succeeded = clearScrollResponse.isSucceeded();
    System.out.println("succeeded:" + succeeded);

    return R.ok();
}