迭代器模式 实现ES大量数据查询

news2024/11/16 5:58:18

目录

项目需求 

要求

普通策略

升级策略:使用迭代器模式

迭代器模式组成

代码实现

查询实体

返回实体

实现类

代码测试

mock的ES返回结果json数据

第一次返回结果

第二次返回结果

第三次返回结果

postMan请求, 控制台打印结果


项目需求 

数据从Mysql 迁移到 Es,  Es查询数据默认fetch Size最大为10000条,如果查询超过1万条,需要通过scroll形式进行查询

要求

  1. 安全问题考虑,查询需要连接ES-ip:9200,不可使用第三方j a r
  2. 由于目前项目的查询方式是基于Mysql,为了减少改动,暂时使用sql进行查询
  3. 需要将结果以stream的形式进行返回,避免内存占用过大,以及瞬时的网络带宽问题

普通策略

  1. 进行第一次访问,然后取columns, rows 和 cursor
  2. 转化我们的第一次结果为map形式的json
  3. 拿第一次的corsor id 进行第二次访问
  4. 用第一次记录的columns 组装第二次的rows结果为map形式的json
  5. 以此类推

升级策略:使用迭代器模式

  1. 将我们访问封装到我们的迭代器中
  2. 第一次访问以迭代器的构造函数访问,初始化我们的columns, 供后续使用, 将第一次的结果转化为map 形式的json供迭代器使用 hasNext里面进行后续的多次访问

迭代器模式组成

  • iterator 抽象迭代器:负责定义访问和遍历元素的接口
  • concreteIterator 具体迭代器:实现迭代器接口,完成容器元素的遍历
  • aggreate抽象容器:容器角色负责提供创建决堤迭代器的角色接口,提供一个类似createiterator()这样的方法, 在Java中一般是 iterator()方法
  • concreteaggreate 具体容器:实现容器接口定义的方法

代码实现

查询实体


/**
 * 第一次查询用query和fetchSize, 后续用返回结果中的游标cursor
 */
@JsonIgnoreProperties
public class EsSqlQuery {
    /**
     * 调用ES的查询的sql
     */
    private String query;
    /**
     * 取出的条数
     */
    private Long fetchSize;
    /**
     * ES返回的游标
     */
    private String cursor;
    
    public EsSqlQuery(String cursor) {
        this.cursor = cursor;
    }

    public EsSqlQuery(String query, Long fetchSize) {
        this.query = query;
        this.fetchSize = fetchSize;
    }

    public String getQuery() {
        return query;
    }

    public void setQuery(String query) {
        this.query = query;
    }

    public Long getFetchSize() {
        return fetchSize;
    }

    public void setFetchSize(Long fetchSize) {
        this.fetchSize = fetchSize;
    }

    public String getCursor() {
        return cursor;
    }

    public void setCursor(String cursor) {
        this.cursor = cursor;
    }
}

返回实体


public class EsSqlResult {
    private List<Map<String,String>> columns;
    private List<List<Object>> rows;
    private String cursor;

    public List<Map<String, String>> getColumns() {
        return columns;
    }

    public void setColumns(List<Map<String, String>> columns) {
        this.columns = columns;
    }

    public List<List<Object>> getRows() {
        return rows;
    }

    public void setRows(List<List<Object>> rows) {
        this.rows = rows;
    }

    public String getCursor() {
        return cursor;
    }

    public void setCursor(String cursor) {
        this.cursor = cursor;
    }
}

实现类

@Component
public class EsQueryProcessor {

    // 1.用stream返回,节省内存
    public Stream<Map<String, Object>> scrollEsStream(String query, Long fetchSize) {
        return StreamSupport.stream(Spliterators
                .spliteratorUnknownSize(new ScrollIterator(query, fetchSize), 0), false);
    }

    // 2.用迭代器模式
    private class ScrollIterator implements Iterator<Map<String, Object>> {

        /**
         * 游标
         */
        private String scrollId;
        /**
         * 字段名集合
         */
        private List<String> columns;
        /**
         * 迭代元素
         */
        Iterator<Map<String, Object>> iterator;
        /**
         * 模拟访问次数
         */
        private int i = 1;

        // 2.1构造函数进行第一次查询, 初始化后续需要使用的columns和iterator,scrollId
        public ScrollIterator(String query, Long fetchSize) {
            // 模拟根据query和fetchSize从ES第一次获取数据
            String jsonName = "es1.json";
            EsSqlResult result = this.getEsSqlResult(jsonName);
            columns = CollStreamUtil.toList(result.getColumns(), u -> u.get("name"));
            this.scrollId = result.getCursor();
            this.iterator = convert(columns, result).iterator();

        }

        // 2.2根据 scrollId 是否为null进行后续访问,直到scrollId为null
        @Override
        public boolean hasNext() {
            return iterator.hasNext() || scrollNext();
        }

        private boolean scrollNext() {
            if (iterator == null || this.scrollId == null) {
                return false;
            }
            i++;
            // 模拟根据query和fetchSize从ES第i次获取数据
            String jsonName = "es" + i + ".json";
            EsSqlResult result = this.getEsSqlResult(jsonName);
            this.scrollId = result.getCursor();
            this.iterator = convert(columns, result).iterator();
            return iterator.hasNext();
        }

        @Override
        public Map<String, Object> next() {
            return iterator.next();
        }

        // 模拟从ES获取查询结果
        private EsSqlResult getEsSqlResult(String jsonName) {
            if (StrUtil.isBlank(jsonName)) {
                return null;
            }
            EsSqlResult result = null;
            List<File> fileList = FileUtil.loopFiles(ResourceUtil.getResource("json").getFile());
            for (File file : fileList) {
                if (jsonName.equals(file.getName())) {
                    String json = FileUtil.readString(file, Charset.forName("UTF-8"));
                    result = JSONObject.parseObject(json, EsSqlResult.class);
                }
            }
            return result;
        }

    }

    // 3.返回结果传统一点 List<Map>
    private List<Map<String, Object>> convert(List<String> columns, EsSqlResult result) {
        List<Map<String, Object>> results = new ArrayList<>();
        for (List<Object> row : result.getRows()) {
            Map<String, Object> map = new HashMap<>();
            for (int i = 0; i < columns.size(); i++) {
                map.put(columns.get(i), row.get(i));
            }
            results.add(map);
        }
        return results;
    }


}

代码测试

@RestController
public class EsController {

    @Autowired
    private EsService esService;

    @GetMapping("/es")
    public Boolean suggestRequirement() {
        return esService.query();
    }


}


public class EsService {

    @Autowired
    private EsQueryProcessor processor;

    public Boolean query() {
        Stream<Map<String, Object>> mapStream = processor.scrollEsStream(null, null);
        mapStream.forEach(x -> System.out.println(x));
        return true;
    }
}

mock的ES返回结果json数据

第一次返回结果

{
  "cursor": "safajfkajskjkasg",
  "columns": [
    {
      "name": "username",
      "type": "String"
    },
    {
      "name": "age",
      "type": "String"
    }
  ],
  "rows": [
    [
      "zhao",
      "11"
    ],
    [
      "qian",
      "22"
    ]
  ]
}

第二次返回结果

{
  "cursor": "safajfkajskjkasg",
  "rows": [
    [
      "sun",
      "33"
    ],
    [
      "li",
      "44"
    ]
  ]
}

第三次返回结果

{
  "rows": [
    [
      "zhou",
      "55"
    ],
    [
      "wu",
      "66"
    ]
  ]
}

postMan请求, 控制台打印结果

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

云计算服务安全指南

声明 本文是学习GB-T 31167-2014 信息安全技术 云计算服务安全指南. 下载地址而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 云计算服务安全退出服务 9.1退出要求 合同到期或其他原因都可能导致客户退出云计算服务&#xff0c;或将数据和业务系统迁…

植物大战僵尸:代码实现自动收集阳光

通过阳光增加的值为切入点&#xff0c;找到自动收集阳光的关键判断并实现自动收集阳光&#xff0c;首先我们猜测当阳光出现后&#xff0c;我们是否会去点击&#xff0c;这个过程必然是由一个判断和一个时钟周期事件来控制的&#xff0c;那么当我们点击下落的阳光以后&#xff0…

DC-UNet:重新思考UNet架构和双通道高效CNN医学图像

摘要 经典UNet的体系架构在某些方面存在着局限性。因此本文对其结构提出了改进。1)设计高效的CNN架构来取代编码器和解码器;2)在最先进的U-Net模型的基础上&#xff0c;应用残差模块来取代编码器和解码器之间的跳过连接来进行改进。 医学图像分割是通过一些自动和半自动的方法…

linux系统中块设备的基本实现方法

大家好&#xff0c;今天主要和大家聊一聊&#xff0c;如何使用linux系统中的块设备的实现方法。 目录 第一&#xff1a;块设备基本简介 第二&#xff1a;块设备驱动框架 第三&#xff1a;实现程序代码实现 第一&#xff1a;块设备基本简介 块设备驱动与字符设备驱动之间的主…

双指针:环形链表II

题目&#xff1a;142. 环形链表 II 我们知道&#xff0c;判断一个链表是否为环是这样的&#xff1a; public boolean hasCycle(ListNode head) {ListNode slow head,quickly head;while(quickly ! null && quickly.next ! null){slow slow.next;quickly quickly.n…

【javaSE】中异常如何处理

目录 文章目录 一、异常的初识 1.1异常的概念 1.2异常的体系结构 1.3异常的分类 二、异常的处理和抛出 2.1防御式编程 2.2异常的抛出 2.3异常的捕获 2.4异常的处理流程 三、自定义异常类 3.1举例&#xff1a;实现一个用户登录功能 一、异常的初识 1.1异常的概念 在…

Perl语法

Perl从许多语言中借用了语法和概念&#xff1a;awk&#xff0c;sed&#xff0c;C&#xff0c;Bourne Shell&#xff0c;Smalltalk&#xff0c;Lisp甚至是英语。每个简单的语句必须以分号&#xff08;;&#xff09;结尾&#xff0c;和Java类似&#xff0c;与Python不同。 一、扩…

【苹果推群发iMessage推】软件安装它起首将消息发送到Apple Push服务器,而后Apple Push服务器将消息发送到装配了应用程序的手机

推荐内容IMESSGAE相关 作者推荐内容iMessage苹果推软件 *** 点击即可查看作者要求内容信息作者推荐内容1.家庭推内容 *** 点击即可查看作者要求内容信息作者推荐内容2.相册推 *** 点击即可查看作者要求内容信息作者推荐内容3.日历推 *** 点击即可查看作者要求内容信息作者推荐…

《小猫猫大课堂》——数组,操作符,常见关键字

更新不易&#xff0c;麻烦多多点赞&#xff0c;欢迎你的提问&#xff0c;感谢你的转发&#xff0c; 最后的最后&#xff0c;关注我&#xff0c;关注我&#xff0c;关注我&#xff0c;你会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我…

Java--方法重写

1&#xff09;概念 重写(override)&#xff1a;也称为覆盖。重写是子类对父类非静态、非private修饰&#xff0c;非final修饰&#xff0c;非构造方法等的实现过程 进行重新编写, 返回值和形参都不能改变。即外壳不变&#xff0c;核心重写&#xff01;重写的好处在于子类可以根据…

VUE动态组件,插槽和自定义指令

文章目录动态组件1.component组件的使用-keep-alive的使用keep-alive生命周期学习keep-alive组件的include和exclude属性include(指定keep-alive的哪些组件可以被缓存,不指定的话默认所有都会被缓存)exclude(排除项,与include刚好相反,二者不能同时使用)插槽v-slot指令v-slot的…

NodeJS - Express使用

文章目录1. 参数1.1 获取URL中的动态参数2. 静态资源2.1 挂载路径前缀3. nodemon4.1路由4.1 路由的匹配过程4.2 模块化路由4.3 为路由模块添加前缀5. 中间件5.1 全局生效的中间件5.2 全局生效中间件的简化形式5.3 中间件的作用5.4 局部生效的中间件5.5 定义多个局部中间件5.6 使…

计算机xxxxxxx

文章目录1.互联网的两大组成部分&#xff08;边缘部分与核心部分&#xff09;的特点是什么&#xff1f;它们的工作方式各有什么特点&#xff1f;2.简述分组交换的要点。3.试从多个方面比较电路交换、报文交换和分组交换的主要优缺点。4.网络协议的三个要素是什么&#xff1f;各…

十二、生产者和消费者问题、队列、线程池

内容 理解消费者、生产者的案例执行过程&#xff0c; 理解用队列方式做消费者、生产者的案例 会使用线程池运行任务, 理解ThreadPoolExecutor7个参数的含义&#xff08;会根据需要 通过参数控制线程池的总数量&#xff09; 匿名内部类里的异常处理 Thread 使用匿名内部类…

VScode中不同目录间python库函数的调用

问题描述 vscode中跨目录的模块调用远不如pycharm中的来的简单&#xff0c;在pycharm中即使是不同库文件夹中子函数也可以进行互相调用。而在VScode中则需要我们手动向其中添加依赖路径。如下相同的文件结构&#xff0c;在pycharm中可以简单的在model_arc_pesudo中导入model中的…

HTTP传输过程

简介 HTTPS是在HTTP的基础上和ssl/tls证书结合起来的一种协议,保证了传输过程中的安全性,减少了被恶意劫持的可能.很好的解决了解决了http的三个缺点&#xff08;被监听、被篡改、被伪装&#xff09; 对称加密和非对称加密 对称加密 即加密的密钥和解密的密钥相同, 非对称加…

1801. 积压订单中的订单总数

插&#xff1a; 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 坚持不懈&#xff0c;越努力越幸运&#xff0c;大家一起学习鸭~~~ 题目&#xff1a; 给你一个二维整数数组 orders &…

【HTMLCSS】运维、后端你该会的前端基本内容

文章目录前言一、HTML5基础1.1、前端开发的核心技术1.2、Web组成标准1.3、HTML 实例1.3.1、第一个网页1.4、 文本标签1.5、转义字符1.6、图片1.7、超链接1.8、列表1.8.1、无序列表1.8.2、有序列表1.8.3、自定义列表1.9、表格1.9.1、合并单元格1.10、表单二、CSS基础2.1、入门2.…

【论文导读】Stable Learning via Sparse Variable Independence

准备follow一下稳定学习的系列论文&#xff0c;从这篇开始吧。 AAAI2023上的&#xff0c;主要是根据前几年稳定学习组提出的SV特征分类、关注稳定的S特征的样本重加权的优化 针对问题和措施&#xff1a; 稳定学习算法采用的样本重加权有弊端&#xff1a; 1&#xff0c;在有限…

ESP8266 SDK开发之AiThinkerIDE_V1.5.2安装、配置以及编写一个程序

【本文发布于https://blog.csdn.net/Stack_/article/details/128509864&#xff0c;未经允许不得转载&#xff0c;转载须注明出处】 前言 乐鑫官方不搞IDE&#xff0c;安信可搞了IDE&#xff0c;但是各版本之间安装配置有差异&#xff0c;还没有文档说明。官方安装配置教程不完…