水一篇,之前写了es分页查询的几种方法,ElasticSearch 分页查询方法from&size,scroll,及search_after浅析,起因是1月份的需求要做一个ES索引内数据聚合导出的需求。

这个ES索引每天有100万左右新增数据,而需求是每月根据不同的条件做聚合统计,并导出数据到csv文件。之前的同事做过一个类似的功能,但是性能很差,基本思路如下,可以简单分析下。

  1. java的job接收导出查询的参数,创建导出执行任务,启动两个线程,一个es查询线程,一个写csv线程
  2. java调用EsClient,进行search_after查询,每一页查询的结果保存到java内存中,并判断累计的结果数量,大于一个设定的数值之后则根据导出时候设定的参数进行聚合,保存到一个Map中
  3. 分页查询结束后,写csv线程读取聚合后的结果写入csv文件

首先,启动两个线程,一个读,一个等待读之后写csv这个其实是不合理的,在所有数据聚合完成之前,写线程就一直处于等待状态。但是这个模式我改动不了,这是目前项目代码里集成的导出任务jar包里的内容,我没法动它,其他很多导出功能也用的这一套代码,所以这边就只能先这样。(也不是说jar包里的逻辑我在外面就没法修改)

接下来,现有的功能是用的search_after查询的,排序字段是子订单id,是无序的。所以只能支持单线程操作,即只能用一个读线程(ReadThread),一页一页的往后翻页查询。且原来的逻辑中有点bug,大于一个设定的数值之后则根据导出时候设定的参数进行聚合。假定这个数值为5万,那么当不断地翻页某次聚合之后总结果数已经大于5万了,那么之后每次进行翻页查询都要把所有数据重新聚合一遍。最终实测,某次导出了300万数据进行聚合,导出任务总共执行超过了6个小时。

根据以上情况,我重新设计了这次的导出功能。

Continue reading