Elasticsearch使用Easy-Es + RestHighLevelClient实现深度分页跳页

注意!!!博主只在测试环境试了一下,没有发到生产环境跑。因为代码还没写完客户说不用弄了( •̩̩̩̩_•̩̩̩̩ ) 也好,少个功能少点BUG

使用from + size的时候发现存在max_result_window=10000的限制,于是研究使用别的方法,最终想出个歪招来实现深度分页跳页。

1、三种分页方式比较

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、实现过程

  • BaseEsMapper构建查询条件
  • RestHighLevelClient实现scroll大分页滚动查询
  • 判断是否跨页,如果跨页滚动拿到两页数据
  • 根据前端分页参数进行数据截取返回

3、实现代码

引入依赖

<dependency>
    <groupId>org.dromara.easy-es</groupId>
    <artifactId>easy-es-boot-starter</artifactId>
    <version>2.0.0</version>
</dependency>
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-client</artifactId>
    <version>7.6.2</version>
</dependency>
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.6.2</version>
</dependency>

SearchResult

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.Data;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Data
public class SearchResult<T> implements Serializable {

    private int total;

    private List<DocBaseEntity<T>> source = new ArrayList<>();

    private JSONObject aggregations;

    private String scrollId;

    public void addData(DocBaseEntity<T> obj){
        source.add(obj);
    }

    public List<T> getDatas(){
        return source.stream().map(DocBaseEntity::getDatas).collect(Collectors.toList());
    }

    public void addDatas(List<DocBaseEntity<T>> objs){
        source.addAll(objs);
    }

    public void setTotal(Object total){
        this.total = Integer.parseInt(String.valueOf(total));
    }

    public JSONObject toJSONObject(){
        return JSONUtil.parseObj(this,true);
    }
}

DocBaseEntity

import cn.hutool.json.JSONObject;
import lombok.Data;
import org.elasticsearch.search.SearchHit;
import java.io.Serializable;

@Data
public class DocBaseEntity<T> implements Serializable {

    private String _index;

    private String _type;

    private String _id;

    private T datas;

    public DocBaseEntity(SearchHit data) {
        this._index = data.getIndex();
        this._type = data.getType();
        this._id = data.getId();
    }

    public DocBaseEntity(JSONObject jsonHits){
        this._index = jsonHits.getStr("_index");
        this._type = jsonHits.getStr("_type");
        this._id = jsonHits.getStr("_id");
    }

    public T getDatas(){
        return datas;
    }

}

RestClientConfig

import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RestClientConfig {
    @Value("${elasticsearch.clientIps}")
    private String clientIps;

    @Value("${elasticsearch.httpPort}")
    private int httpPort;

    @Value("${elasticsearch.username}")
    private String username;

    @Value("${elasticsearch.password}")
    private String password;

    private HttpHost[] getHttpHosts(String clientIps, int esHttpPort) {
        String[] clientIpList = clientIps.split(",");
        HttpHost[] httpHosts = new HttpHost[clientIpList.length];
        for (int i = 0; i < clientIpList.length; i++) {
            httpHosts[i] = new HttpHost(clientIpList[i], esHttpPort, "http");
        }
        return httpHosts;
    }

    /**
     * 创建带HTTP Basic Auth认证rest客户端
     */
    @Bean
    public RestHighLevelClient restHighLevelClient() {
        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
        return new RestHighLevelClient(RestClient.builder(getHttpHosts(clientIps, httpPort)).setHttpClientConfigCallback((HttpAsyncClientBuilder httpAsyncClientBuilder) -> httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider)));
    }
}

滚动查询方法

@Autowired
private RestHighLevelClient restHighLevelClient;

/**
 * 滚动查询
 * @param indexName
 * @param pageNo
 * @param pageSize
 * @param scrollId
 * @param resultObj
 * @param wrapper
 * @param <T>
 * @return
 * @throws IOException
 */
public <T> SearchResult<T> scrollSearchElasticSearchDatas(String indexName,
                                                          int pageNo,
                                                          int pageSize,
                                                          String scrollId,
                                                          Class<T> resultObj,
                                                          LambdaEsQueryWrapper<ES实体类Bean> wrapper) throws IOException {
    SearchSourceBuilder searchSourceBuilder = rdsBookCommonDetailEsMapper.getSearchSourceBuilder(wrapper);
    searchSourceBuilder.size(pageSize);
    SearchRequest searchRequest = new SearchRequest(indexName);
    searchRequest.source(searchSourceBuilder);
    //设定scroll失效时长
    Scroll scroll = new Scroll(TimeValue.timeValueMinutes(3));
    searchRequest.scroll(scroll);
    SearchResponse searchResponse = null;
    if(StrUtil.isEmpty(scrollId)){
        searchResponse = executSearch(searchRequest);
        String tempscrollId = searchResponse.getScrollId();
        SearchScrollRequest searchScrollRequest = new SearchScrollRequest(tempscrollId);
        searchScrollRequest.scroll(scroll);
        for (int i = 0; i < (pageNo -1); i++) {
            searchResponse = scrollSearch(searchScrollRequest);
        }
        scrollId = tempscrollId;
    }else {
        SearchScrollRequest searchScrollRequest = new SearchScrollRequest(scrollId);
        searchResponse = scrollSearch(searchScrollRequest);
    }
    //构建结果
    SearchResult<T> result = createSearchResult(searchResponse,resultObj);
    result.setScrollId(scrollId);
    return result;
}

/**
 * 执行查询
 */
private SearchResponse executSearch(SearchRequest searchRequest)     {
    SearchResponse searchResponse = null;
    try{
        searchResponse = restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);
    }catch(Exception e){
        //异常处理
    }
    return searchResponse;
}

/**
 * 滚动查询执行
 * @param searchScrollRequest
 * @return
 */
private  SearchResponse scrollSearch(SearchScrollRequest searchScrollRequest){
    SearchResponse searchResponse = null;
    try{
        searchResponse = restHighLevelClient.scroll(searchScrollRequest,RequestOptions.DEFAULT);
    }catch(Exception e){
        //异常处理
    }
    return searchResponse;
}

/**
 * 构建目标结果
 * @param response 返回参数
 * @param resultObj 类对象
 * @param <T>
 * @return
 */
private <T> SearchResult<T> createSearchResult(SearchResponse response,Class<T> resultObj){
    SearchResult<T> resultMap = new SearchResult<>();
    SearchHit[] datas = response.getHits().getHits();
    for(SearchHit data:datas){
        DocBaseEntity<T> temp = new DocBaseEntity<>(data);
        temp.setDatas(JSONUtil.toBean(JSONUtil.parseObj(data.getSourceAsMap()),resultObj));
        resultMap.addData(temp);
    }
    resultMap.setTotal(response.getHits().getTotalHits().value);
    return resultMap;
}

/**
 * 关闭scroll
 * @param scrollId
 * @throws IOException
 */
private void clearScrollSession(String scrollId) throws IOException {
    if (scrollId != null) {
        ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
        clearScrollRequest.addScrollId(scrollId);
        ClearScrollResponse clearScrollResponse = restHighLevelClient.clearScroll(clearScrollRequest, RequestOptions.DEFAULT);
        clearScrollResponse.isSucceeded();
    }
}

使用

LambdaEsQueryWrapper<ES实体类Bean> wrapper = new LambdaEsQueryWrapper<>();
wrapper.eqxxx
...构建各种查询条件
// 游标id
String scrollId = "";
// 第一次查询
SearchResult<ES实体类Bean> firstSearchResult = null;
// 第二次查询
SearchResult<ES实体类Bean> secondSearchResult = null;
// 每次滚动查询5000条数据,根据前端传的分页参数决定要滚动到哪一页
int maxPage = ((searchCommonDetaiVo.getCurrentPage() * searchCommonDetaiVo.getPageSize()) / 5000) + 1;
try {
	firstSearchResult = scrollSearchElasticSearchDatas("IndexName", maxPage, 5000, scrollId, ES实体类Bean.class, wrapper);
	scrollId = firstSearchResult.getScrollId();
} catch (IOException e) {
	e.printStackTrace();
}
// 判断是否跨页
if (searchCommonDetaiVo.getPageSize() > (searchCommonDetaiVo.getCurrentPage() * searchCommonDetaiVo.getPageSize()) % 5000) {
	try {
		secondSearchResult = scrollSearchElasticSearchDatas("IndexName", maxPage-1, 5000, scrollId, ES实体类Bean.class, wrapper);
	} catch (IOException e) {
		e.printStackTrace();
	}
}
// TODO 根据前端分页参数截取数据返回
try {
	clearScrollSession(scrollId);
} catch (IOException e) {
	log.info("游标清理失败");
	e.printStackTrace();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/887046.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何使用工具删除 iPhone 上的图片背景

在 iPhone 上删除背景图像变得简单易行。感谢最近 iOS 更新中引入的新功能。如今&#xff0c;iOS 用户现在可以毫不费力地删除背景&#xff0c;而无需复杂的应用程序。在这篇文章中&#xff0c;您将学习如何使用各种方法去除 iPhone 上的背景。这可确保您可以选择最适合您偏好的…

自动驾驶核心技术:感知融合、规划决策、控制执行

1、前言 简单来说&#xff0c;实现自动驾驶需要解决三个核心问题&#xff1a;“我在哪?我要去哪?我该如何去?”能完整解决这三个问题就是真正的自动驾驶。 目前&#xff0c;自动驾驶汽车关键技术主要包括环境感知、精准定位、决策与规划、控制与执行、高精地图与车联网V2X以…

Linux下的IO模型

阻塞与非阻塞IO&#xff08;Input/Output&#xff09; 阻塞与非阻塞IO&#xff08;Input/Output&#xff09;是计算机操作系统中两种不同的文件或网络通信方式。它们的主要区别在于程序在等待IO操作完成时的行为。 阻塞IO&#xff08;Blocking IO&#xff09; 在阻塞IO模式下…

无IDEA不Java:快速掌握Java集成开发环境

IntelliJ IDEA是一种强大的Java集成开发环境&#xff0c;是Java开发人员的首选工具之一。本文将介绍IDEA的基本使用方法和常用功能&#xff0c;以帮助初学者快速上手。 安装和配置 首先&#xff0c;需要下载并安装IntelliJ IDEA。在安装完成后&#xff0c;需要配置JDK&#xff…

pygame--超级马里奥(万字详细版)

超级马里奥点我下载https://github.com/marblexu/PythonSuperMario 1.游戏介绍 小时候的经典游戏&#xff0c;代码参考了github上的项目Mario-Level-1&#xff0c;使用pygame来实现&#xff0c;从中学习到了横版过关游戏实现中的一些处理方法。原项目实现了超级玛丽的第一个小…

稀缺森林火险等级预测算法,基于xgboost方法的火险等级预测,共划分5级,依据当前地区月份,降水量,风力等参数进行预测,并提供15000字的报告

森林火险等级预测算法&#xff0c;基于xgboost方法的火险等级预测&#xff0c;共划分5级&#xff0c;依据当前地区月份&#xff0c;降水量&#xff0c;风力等参数进行预测&#xff0c;并提供15000字的报告 森林火险等级预测算法介绍 项目名称 基于XGBoost的森林火险等级预测算…

无环SLAM系统集成后端回环检测模块(loop):SC-A-LOAM以及FAST_LIO_SLAM

最近在研究SLAM目标检测相关知识&#xff0c;看到一篇论文&#xff0c;集成了SC-A-LOAM作为后端回环检测模块&#xff0c;在学习了论文相关内容后决定看一下代码知识&#xff0c;随后将其移植&#xff0c;学习过程中发现我找的论文已经集成了回环检测模块&#xff0c;但是我的另…

mybatis-plus使用总结

基本使用 mybatis-plus依赖 <!-- mybatis-plus开始 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.7</version></dependency><dependency>&l…

【Linux探索学习】第二弹——Linux的基础指令(中)——夯实基础第二篇

Linux基础指令&#xff08;上&#xff09;&#xff1a;【Linux探索学习】第一弹——Linux的基本指令&#xff08;上&#xff09;——开启Linux学习第一篇-CSDN博客 前言&#xff1a; 在前面我们已经讲解了一些常用的Linux的基础指令&#xff0c;那些当然是远远不够的&#xff…

自定义 shell文件系统

&#x1f3f7;️ 材料准备 创建一个文件:myshell.c: #include <stdio.h>int main() {return 0; }创建一个 Makefile 文件&#xff0c;文件内容如下&#xff1a; 1 mybash:myshell.c2 g -o $ $^ -stdc11 3 .PHONY:…

仿RabbitMQ实现消息队列服务端(二)

文章目录 ⽹络通信协议设计信道管理模块连接管理模块服务器模块实现 ⽹络通信协议设计 其中⽣产者和消费者都是客⼾端&#xff0c;它们都需要通过⽹络和BrokerServer进⾏通信。具体通信的过程我们使⽤Muduo库来实现&#xff0c;使⽤TCP作为通信的底层协议&#xff0c;同时在这个…

【智能大数据分析 | 实验二】Spark实验:部署Spark集群

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈智能大数据分析 ⌋ ⌋ ⌋ 智能大数据分析是指利用先进的技术和算法对大规模数据进行深入分析和挖掘&#xff0c;以提取有价值的信息和洞察。它结合了大数据技术、人工智能&#xff08;AI&#xff09;、机器学习&#xff08;ML&a…

如何编写一个优雅的commit message

在Git中&#xff0c;git commit 命令扮演着至关重要的角色。它的主要作用是将暂存区&#xff08;staging area&#xff09;里的改动内容提交到本地仓库&#xff08;repository&#xff09;中&#xff0c;形成一个新的版本或提交&#xff08;commit&#xff09;。这个过程是 Git…

【HarmonyOS】时间处理Dayjs

背景 在项目中经常会使用要时间的格式转换&#xff0c;比如数据库返回一个Date数据&#xff0c;你需要转成2024-10-2的格式&#xff0c;鸿蒙的原生SDK中是没有办法实现的&#xff0c;因此&#xff0c;在这里介绍第三方封装好并且成熟使用的库Dayjs。 安装 切换到Entry文件夹下…

【学习资源】人在环路的机器学习

说明&#xff1a;本文图片和内容来源 Human-in-the-Loop Machine Learning Human-in-the-Loop Machine Learning Active learning and annotation for human-centered AI by Robert (Munro) Monarch, June 2021 介绍Human-in-the-Loop的目标&#xff0c;学习过程&#xff0c…

gdb 调试 linux 应用程序的技巧介绍

使用 gdb 来调试 Linux 应用程序时&#xff0c;可以显著提高开发和调试的效率。gdb&#xff08;GNU 调试器&#xff09;是一款功能强大的调试工具&#xff0c;适用于调试各类 C、C 程序。它允许我们在运行程序时检查其状态&#xff0c;设置断点&#xff0c;跟踪变量值的变化&am…

基于Arduino的宠物食物分配器

创作本文的初衷是本人的一个养宠物的梦想&#xff08;因为家里人对宠物过敏&#xff0c;因此养宠物的action一直没有落实&#xff09;&#xff0c;但是梦想总是要有的哈哈哈哈哈。上周正好是和一个很好的朋友见面&#xff0c;聊到了养宠物的事情&#xff0c;她大概是讲到了喂宠…

震撼!工业史上第一家万级别规模的工业数字化设备效果图平台

耗时八年打造&#xff0c;国内第一家万级别规模的工业数字化设备效果图平台 平台&#xff1a;www.kingview3d.cn 创作者&#xff1a;kingview3d郭工 行业&#xff1a;煤矿综合自动化、污水处理、净水处理、楼宇暖通、环保工程、医药废水处理、二供、无负压加压站、提升泵站、一…

《NoSQL》非关系型数据库MongoDB 学习笔记!

Mongo基础&#xff1a; 使用数据库&#xff1a; 使用use 命令 后面跟着要使用的数据库名字即可&#xff0c; 例如&#xff1a;use cities, 值得注意的是&#xff0c; mongo中不像mysql&#xff0c; 还需要先创建数据库&#xff0c;后访问&#xff0c; mongo中&#xff0c;你无…

【WebGis开发 - Cesium】如何确保Cesium场景加载完毕

目录 引言一、监听场景加载进度1. 基础代码2. 加工代码 二、进一步封装代码1. 已知存在的弊端2. 封装hooks函数 三、使用hooks方法1. 先看下效果2. 如何使用该hooks方法 三、总结 引言 本篇为Cesium开发的一些小技巧。 判断Cesium场景是否加载完毕这件事是非常有意义的。 加载…