This is an automated email from the ASF dual-hosted git repository.

gaoxihui pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozhera.git


The following commit(s) were added to refs/heads/master by this push:
     new 01527252 refactor(log-export): refactor log export logic (#607)
01527252 is described below

commit 01527252ea436a27915561da305a2ad14a86d5e5
Author: Xue <[email protected]>
AuthorDate: Mon Oct 13 16:42:58 2025 +0800

    refactor(log-export): refactor log export logic (#607)
    
    * refactor(log-export): refactor log export logic and remove 5000-row limit
    
    Reworked the log export implementation to handle larger datasets 
efficiently.
    Removed the hard-coded 5000-row limit and introduced a more flexible export 
mechanism.
    
    * fix: fix missing data issue caused by sorting and update Excel export to 
new version
---
 .../ozhera/log/manager/domain/SearchLog.java       |  29 ++++++
 .../ozhera/log/manager/model/vo/LogQuery.java      |   3 +
 .../manager/service/impl/EsDataServiceImpl.java    | 116 ++++++++++++++++++---
 3 files changed, 134 insertions(+), 14 deletions(-)

diff --git 
a/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/domain/SearchLog.java
 
b/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/domain/SearchLog.java
index f06dd338..bc19a63b 100644
--- 
a/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/domain/SearchLog.java
+++ 
b/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/domain/SearchLog.java
@@ -32,6 +32,8 @@ import 
com.xiaomi.youpin.docean.plugin.es.antlr4.common.util.EsQueryUtils;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
 import org.elasticsearch.index.query.BoolQueryBuilder;
 import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.index.query.QueryBuilders;
@@ -341,6 +343,33 @@ public class SearchLog {
         }
     }
 
+    public void downLogFileV2(Workbook excel, String fileName) throws 
IOException {
+        File file = null;
+        FileOutputStream fos = null;
+        try {
+            file = new File(DoceanConfig.ins().get("download_file_path", 
"/tmp") + File.separator + fileName);
+            file.createNewFile();
+            fos = new FileOutputStream(file);
+            excel.write(fos);
+            Down.down(fileName);
+        } catch (Exception e) {
+            log.error("downLogFile error,fileName:{}", fileName, e);
+        } finally {
+            if (excel != null) {
+                excel.close();
+                if (excel instanceof SXSSFWorkbook sxssf) {
+                    sxssf.dispose();
+                }
+            }
+            if (fos != null) {
+                fos.close();
+            }
+            if (file != null) {
+                file.delete();
+            }
+        }
+    }
+
     public String esHistogramInterval(Long duration) {
         duration = duration / 1000;
         if (duration > 24 * 60 * 60) {
diff --git 
a/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/model/vo/LogQuery.java
 
b/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/model/vo/LogQuery.java
index 4c778b8a..ca146c22 100644
--- 
a/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/model/vo/LogQuery.java
+++ 
b/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/model/vo/LogQuery.java
@@ -42,6 +42,9 @@ public class LogQuery implements Serializable {
     private Long[] appIds;
     private String statField;
 
+    private Object[] searchAfter;
+    private Boolean isDownload = false;
+
     public LogQuery() {
     }
 
diff --git 
a/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/service/impl/EsDataServiceImpl.java
 
b/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/service/impl/EsDataServiceImpl.java
index 8f1a00e1..9014c57b 100644
--- 
a/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/service/impl/EsDataServiceImpl.java
+++ 
b/ozhera-log/log-manager/src/main/java/org/apache/ozhera/log/manager/service/impl/EsDataServiceImpl.java
@@ -65,7 +65,9 @@ import 
org.apache.ozhera.log.manager.service.HeraAppEnvService;
 import 
org.apache.ozhera.log.manager.service.extension.common.CommonExtensionService;
 import 
org.apache.ozhera.log.manager.service.extension.common.CommonExtensionServiceFactory;
 import org.apache.ozhera.log.parse.LogParser;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
 import org.elasticsearch.ElasticsearchStatusException;
 import org.elasticsearch.action.search.SearchRequest;
 import org.elasticsearch.action.search.SearchResponse;
@@ -76,7 +78,6 @@ import org.elasticsearch.search.builder.SearchSourceBuilder;
 import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.StopWatch;
-import run.mone.excel.ExportExcel;
 
 import javax.annotation.Resource;
 import javax.sql.DataSource;
@@ -399,12 +400,21 @@ public class EsDataServiceImpl implements EsDataService, 
LogDataService, EsDataB
         builder.query(boolQueryBuilder);
 
         builder.sort(commonExtensionService.getSortedKey(logQuery, 
logQuery.getSortKey()), logQuery.getAsc() ? ASC : DESC);
-        if (null != logQuery.getPage()) {
-            builder.from((logQuery.getPage() - 1) * logQuery.getPageSize());
+        if (logQuery.getSearchAfter() != null && logQuery.getIsDownload()){
+            builder.from(0);
+            builder.size(logQuery.getPageSize());
+            builder.searchAfter(logQuery.getSearchAfter());
+        }else {
+            if (null != logQuery.getPage()) {
+                builder.from((logQuery.getPage() - 1) * 
logQuery.getPageSize());
+            }
+            builder.size(logQuery.getPageSize());
+        }
+
+        // highlight, it is only necessary when not downloading.
+        if(!logQuery.getIsDownload()){
+            builder.highlighter(getHighlightBuilder(keyList));
         }
-        builder.size(logQuery.getPageSize());
-        // highlight
-        builder.highlighter(getHighlightBuilder(keyList));
         builder.timeout(TimeValue.timeValueMinutes(2L));
         return builder;
     }
@@ -737,17 +747,95 @@ public class EsDataServiceImpl implements EsDataService, 
LogDataService, EsDataB
     public void logExport(LogQuery logQuery) throws Exception {
         log.info("Log query, logExport, logQuery:{}", GSON.toJson(logQuery));
         // Generate Excel
-        int maxLogNum = 5000;
-        logQuery.setPageSize(maxLogNum);
-        Result<LogDTO> logDTOResult = this.logQuery(logQuery);
-        List<Map<String, Object>> exportData = logDTOResult.getCode() != 
CommonError.Success.getCode() || logDTOResult.getData().getLogDataDTOList() == 
null || logDTOResult.getData().getLogDataDTOList().isEmpty() ? null : 
logDTOResult.getData().getLogDataDTOList().stream().map(logDataDto -> 
ExportUtils.SplitTooLongContent(logDataDto)).collect(Collectors.toList());
-        HSSFWorkbook excel = ExportExcel.HSSFWorkbook4Map(exportData, 
generateTitle(logQuery));
+        final int rowsPerSheet = 5000; //each sheet is fixed at 5000 rows
+        final int maxPage = 100; //max pages, the upper limit of the number of 
rows: 5000*100
+        int page = 1;
+        Workbook workbook = new SXSSFWorkbook();
+        String title = generateTitle(logQuery);
+        List<String> headers = null;
+        Object[] lastSortValues = null;
+        logQuery.setIsDownload(true);
+        while(page <= maxPage) {
+            logQuery.setPageSize(rowsPerSheet);
+            logQuery.setPage(page);
+            //Prevent errors when performing deep paging in the ES database
+            logQuery.setSearchAfter(lastSortValues);
+
+            Result<LogDTO> logDTOResult = this.logQuery(logQuery);
+            if (logDTOResult.getCode() != CommonError.Success.getCode() || 
logDTOResult.getData() == null || logDTOResult.getData().getLogDataDTOList() == 
null || logDTOResult.getData().getLogDataDTOList().isEmpty()) {
+                break;
+            }
+            List<Map<String, Object>> list = 
logDTOResult.getData().getLogDataDTOList().stream().map(logDataDto -> 
ExportUtils.SplitTooLongContent(logDataDto)).collect(Collectors.toList());
+
+            if (list == null || list.isEmpty()) {
+                break;
+            }
+
+            if (page == 1){
+                headers = new ArrayList<>(list.getFirst().keySet());
+            }
+
+            //If the table header is empty, then obtain the header from the 
current page.
+            if (headers == null || headers.isEmpty()) {
+                headers = new ArrayList<>(list.getFirst().keySet());
+            }
+
+            Sheet sheet = workbook.createSheet("Sheet" + page);
+            int dataBeginRow;
+
+            if (title != null && !title.isEmpty() && page == 1) {  //only the 
first sheet has a title
+                Row titleRow = sheet.createRow(0);
+                Cell cell = titleRow.createCell(0);
+                cell.setCellValue(title);
+                CellStyle titleStyle = workbook.createCellStyle();
+                titleStyle.setAlignment((short)2);
+                titleStyle.setVerticalAlignment((short)1);
+                Font titleFont = workbook.createFont();
+                titleFont.setBoldweight((short)700);
+                titleStyle.setFont(titleFont);
+                cell.setCellStyle(titleStyle);
+                titleRow.setHeight((short)450);
+                dataBeginRow = list != null && !list.isEmpty() ? 
((Map)list.get(0)).size() - 1 : 5;
+                sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 
dataBeginRow));
+            }
+
+            if (list != null && !list.isEmpty()) {
+                CellStyle headerStyle = workbook.createCellStyle();
+                headerStyle.setAlignment((short)2);
+                headerStyle.setBorderBottom((short)2);
+                headerStyle.setBorderTop((short)2);
+                int headRowIndex = title != null && !title.isEmpty() && page 
== 1 ? 1 : 0;
+                Row headRow = sheet.createRow(headRowIndex);
+                int i = 0;
+                for (String h : headers){
+                    Cell cell = headRow.createCell(i++);
+                    cell.setCellValue(h);
+                    cell.setCellStyle(headerStyle);
+                }
+
+                dataBeginRow = title != null && !title.isEmpty() && page == 1 
? 2 : 1;
+
+                for(int j = 0; j < list.size(); ++j) {
+                    Row row = sheet.createRow(dataBeginRow++);
+                    Map<String, Object> rowMap = list.get(j);
+                    for (int k = 0; k < headers.size(); k++){
+                        Cell cell = row.createCell(k);
+                        Object val = rowMap.get(headers.get(k));
+                        cell.setCellValue(val == null ? "" : val.toString());
+                    }
+                }
+            }
+            lastSortValues = logDTOResult.getData().getThisSortValue();
+            page++;
+        }
         // Download
-        String fileName = String.format("%s_log.xls", logQuery.getLogstore());
-        searchLog.downLogFile(excel, fileName);
+        String fileName = String.format("%s_log.xlsx", logQuery.getLogstore());
+        searchLog.downLogFileV2(workbook, fileName);
     }
 
     private String generateTitle(LogQuery logQuery) {
         return String.format("%sLogs, search terms:[%s],time range%d-%d", 
logQuery.getLogstore(), logQuery.getFullTextSearch() == null ? "" : 
logQuery.getFullTextSearch(), logQuery.getStartTime(), logQuery.getEndTime());
     }
+
+
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to