Easy-Es框架异步分页查询问题记录

文章讲述了作者在优化导出Excel时,将查询从BD改为ES并使用线程池,遇到数据条数不匹配的问题。问题源于Easy-Es分页查询时,线程池共享的Wrapper导致数据安全问题。作者提醒在使用线程池时务必注意线程安全,尤其是分页参数的传递。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在做导出excel优化,就把查询BD改成了查ES,并且使用了线程池。就出现了导出数据的条数对不上的问题。最终发现easy-es在分页的时候往传入的wrapper中设置的from和size,由于使用线程池传入的wrapper是同一个就出现了数据安全问题,所有就此记录一下问题,在使用线程池时一定要注意线程安全。

// 这是Easy-Es框架封装的分页查询方法
 public EsPageInfo<T> pageQuery(Wrapper<T> wrapper, Integer pageNum, Integer pageSize) {
        // 兼容分页参数
        pageNum = pageNum == null || pageNum <= BaseEsConstants.ZERO ? BaseEsConstants.PAGE_NUM : pageNum;
        pageSize = pageSize == null || pageSize <= BaseEsConstants.ZERO ? BaseEsConstants.PAGE_SIZE : pageSize;

        wrapper.from = (pageNum - 1) * pageSize;
        wrapper.size = pageSize;

        // 请求es获取数据
        SearchResponse response = getSearchResponse(wrapper);

        // 解析数据
        SearchHit[] searchHits = parseSearchHitArray(response);
        List<T> dataList = Arrays.stream(searchHits)
                .map(searchHit -> parseOne(searchHit, wrapper))
                .collect(Collectors.toList());
        long count = parseCount(response, Objects.nonNull(wrapper.distinctField));
        return PageHelper.getPageInfo(dataList, count, pageNum, pageSize);
    }
ambdaEsQueryWrapper<BizEsWaybillEntity> countWrapper = new LambdaEsQueryWrapper<>();
			getEsQueryParam(query,countWrapper);
			Long countTime = System.currentTimeMillis();
			Integer totalCount = esWaybillMapper.selectCount(countWrapper).intValue();
			log.info("查询es运单总条数:{}条,耗时:{}毫秒",totalCount, System.currentTimeMillis() - countTime);
			totalNum = totalCount / pageSize + 1;
			if (totalNum > 1) {
				List<CompletableFuture<Integer>> futureList = new ArrayList<>();
				ExcelWriter finalExcelWriter = excelWriter;
				for (Integer i = 0; i < totalNum; i++) {
					Integer finalI = i + 1;
					CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
					
						// easy-es中的分页参数是往传入的wrapper中赋值,所有使用线程池并发每次查询都需要传入新的wrapper
						LambdaEsQueryWrapper<BizEsWaybillEntity> wrapper = new LambdaEsQueryWrapper<>();
						getEsQueryParam(query,wrapper);
						List<BizEsWaybillEntity> bizWaybillVos = getBizEsWaybillEntities(wrapper, finalI, pageSize, finalExcelWriter, writeSheet);
					
						return CollectionUtils.isNotEmpty(bizWaybillVos) ? bizWaybillVos.size() : 0;
					}, downloadTaskExecutor);

					futureList.add(future);
				}
				// 等待所有任务完成
				allOf(futureList, startTime);
			} else {
				List<BizEsWaybillEntity> bizWaybillVos = getBizEsWaybillEntities(countWrapper, 1, pageSize, excelWriter, writeSheet);
				log.info("导出运单数量:{},耗时:{}", bizWaybillVos.size(), System.currentTimeMillis() - startTime);
			}
根据提供的引用内容,没有找到关于ES多线程分组分页查询的信息。不过,ES支持多线程查询和分组分页查询,可以分别介绍一下。 1. ES多线程查询 ES支持多线程查询,可以通过设置线程池来控制并发查询的数量。以下是一个使用Python Elasticsearch库进行多线程查询的例子: ```python from elasticsearch import Elasticsearch from elasticsearch.helpers import parallel_bulk from multiprocessing import Pool es = Elasticsearch() def process_data(data): # 处理数据的函数 pass def index_data(data): # 索引数据的函数 pass def run_query(query): # 运行查询的函数 pass def run_parallel_bulk(data): with Pool(processes=4) as pool: for success, info in parallel_bulk(es, data, index='my-index', chunk_size=1000, thread_count=4): if not success: print('A document failed:', info) ``` 在上面的例子中,我们使用了Python的multiprocessing库来创建一个进程池,然后使用Elasticsearch的parallel_bulk函数来并发地索引数据。 2. ES分组分页查询 ES支持分组分页查询,可以使用Elasticsearch的search方法来实现。以下是一个使用Python Elasticsearch库进行分组分页查询的例子: ```python from elasticsearch import Elasticsearch es = Elasticsearch() def search_data(): query = { "size": 0, "aggs": { "group_by_field": { "terms": { "field": "my_field", "size": 10 }, "aggs": { "group_by_date": { "date_histogram": { "field": "my_date_field", "interval": "day" }, "aggs": { "sum_by_field": { "sum": { "field": "my_sum_field" } } } } } } } } res = es.search(index="my-index", body=query) return res ``` 在上面的例子中,我们使用了Elasticsearch的聚合功能来进行分组分页查询。我们首先按照my_field字段进行分组,然后按照my_date_field字段进行日期直方图聚合,最后对my_sum_field字段进行求和聚合。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值