Apache Poi处理ES百万级数据的导出案例

背景:

  1. 导出竞品周报(月报)数据
  2. 一个任务导出多个Excel   数据表。
  3. 数据表数据大于100万时,分割成两个数据表。

功能点:

  1. 异步导出
  2. 从ES中获取数据时,仅返回需要的字段,节省内存
  3. 将获取的数据做分割,按照品牌分类,存于map中
  4. 当单表数据量超过100万时,需要做数据分割,分割成多个数据表,单表最大100万
  5. 将导出文件,打成压缩包
  6. 使用SXSSFWorkbook进行数据导出,避免内存溢出

          设置窗口大小 swb = new SXSSFWorkbook(wb, 1000);

          设置压缩临时文件 swb.setCompressTempFiles(true);

核心逻辑: 

结果:

 导出数量:5513997

导出时间:67分钟

 

代码:

private String createExcelReport(Map.Entry<String, List<AnalysisIndustryBean>> entry, String filePath,
                                            DownloadInfo downloadInfo, HashMap<String, Object> timeMap,
                                            Map<Integer, String> monitorMap, HashMap<Integer, Object> labelMap) throws Exception {
        String result = ResultCommon.LOSE_CODE;
        XSSFWorkbook wb = null;
        Sheet sheet = null;
        FileInputStream in = null;
        FileOutputStream out = null;
        List<AnalysisIndustryBean> beanList = null;
        SXSSFWorkbook swb = null;
        BufferedOutputStream bos = null;
        try {
            // 检测项名称
            String monitorName = monitorMap.get(Integer.valueOf(entry.getKey()));
            System.out.println("[" + DateHelper.getNowDate(DateHelper.FMT_DATE_DATETIME) + "]--------" + monitorName + "(执行中)----------");
            String startTime = DateHelper.formatDateString((String) timeMap.get("startTime"), DateHelper.FMT_DATE_DATETIME, DateHelper.FMT_DATE_YYMMDD);
            String endTime = DateHelper.formatDateString((String) timeMap.get("endTime"), DateHelper.FMT_DATE_DATETIME, DateHelper.FMT_DATE_YYMMDD);
            // 报告名称
            String tempFileName = monitorName + "-" + startTime + "-" + endTime + "周报数据";
            // 需要导出报告数据
            beanList = entry.getValue();
            // 模板路径
            String templatePath = ExcelReportCommonData.WEEKLY_EXCEL_REPORT_PATH;
            in = new FileInputStream(templatePath);
            wb = new XSSFWorkbook(in);
            swb = new SXSSFWorkbook(wb, 1000);
            swb.setCompressTempFiles(true); // 设置压缩文件
            swb.setSheetName(0, monitorName);
            sheet = swb.getSheetAt(0);
            this.styles = com.xlmediawatch.common.Style.ExcelStyle.createStyle(wb);//excel的样式
            int rowNum = 1; // 记录行数
            int serialNum = 1; // 序号

            if (beanList != null && !beanList.isEmpty()) {
                int fileCount = 1; // 计数器,用于生成文件序号
                for (int i = 0; i < beanList.size(); i++) {
                    AnalysisIndustryBean esBean = beanList.get(i);
                    // 每五个元素创建一个新的 Excel 文件,或者到达列表末尾时
                    if (i > 0 && i % 1000000 == 0) {
                        // 输出数据
                        String fileName = i / 1000000 == 1 ? tempFileName + ".xlsx" : tempFileName + "(" + (fileCount - 1) + ").xlsx";
                        out = new FileOutputStream(filePath + fileName);
                        bos = new BufferedOutputStream(out);
                        bos.flush();
                        swb.write(bos);

                        // 重置
                        in = new FileInputStream(templatePath);
                        wb = new XSSFWorkbook(in);
                        swb = new SXSSFWorkbook(wb, 1000);
                        swb.setCompressTempFiles(true); // 设置压缩文件
                        swb.setSheetName(0, monitorName);
                        sheet = swb.getSheetAt(0);
                        // 多个excel之间样式不能共享,所以每个excel都需要重新赋值styles
                        this.styles = com.xlmediawatch.common.Style.ExcelStyle.createStyle(wb);//excel的样式
                        rowNum = 1; // 记录行数
                        serialNum = 1; // 序号
                        fileCount++; // 文件序号递增
                    }
                    // 填充数据
                    rowNum = createMonitorExcelReportData(rowNum, esBean, serialNum, sheet, monitorName, labelMap);
                    serialNum++;
                }
                // 写出最后一个文件,如果列表大小不是5的整数倍时
                if (!beanList.isEmpty()) {
                    String fileName = fileCount == 1 ? tempFileName + ".xlsx" : tempFileName + "(" + (fileCount - 1) + ").xlsx";
                    out = new FileOutputStream(filePath + fileName);
                    bos = new BufferedOutputStream(out);
                    bos.flush();
                    swb.write(bos);
                }
            }
            result = ResultCommon.SUSSES_CODE;
        } catch (IOException e) {
            result = ResultCommon.LOSE_CODE;
            e.printStackTrace();
        } finally {
            // 关闭资源
            try {
                if (bos != null) {
                    bos.close();
                }
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
                if (swb != null) {
                    swb.dispose();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return result;
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值