问题背景
公司有个业务场景就是在程序中将ES聚合的数据按照管理平台的配置,对ES聚合返回的集合中指定匹配的元素进行置顶
(所谓置顶:将元素往集合的前面放)
落地方案
v1.0
傻瓜式操作:
将ES聚合数据进行遍历,然后equals配置项,将匹配到的document存放到新的集合中,遍历结束后,将新的集合添加至ES聚合的document集合前面。
此方案缺点:
当聚合数据量较少时,此操作OK,不会带来太大的性能问题,若当ES
聚合的数据量到大一个量级时,比如说10W以上,此方案就显得力不从心了,于是我就想出了下面的方案
v1.1
具体流程
1.在数据处理插件中对ES召回的数据量进行判断,当超过指定的阈值时就采用分治来实现(数据分段,多线程),反之,就走v1.0的流程,
这里有人就会问了为什么还是要继续沿用v1.0的=办法,而不是直接全部走分治?
我的思考是:多线程毕竟会考虑到CPU资源分配,时间片轮转等问题,当数据量较小时还不如直接使用for each遍历来得快(注意 使用for each 而不是for 循环,因为for是基于线性表的索引操作,而for each是基于iterator的指针操作,所以对于非固定索引查找时,链表的索引效率是较高的)
2.当数据量大时的分治思想落地:
这里落地方案是:
使用JDK1.8 parallelStream 进行并行处理(关于stream的使用和原理,各位自行官网学习)
下面是伪代码:
// ES聚合的list
List<Document> esList ;
// 用于存放从ES中匹配到的置顶项Document
// 注意要考虑线程安全问题:多个线程同时add
List<Document> newList= new ArrayList<>();
newList = Collections.synchronizedList(newList);
esList.parallelStream().forEach(d-> {
// 这里是处理置顶的过程
})
结束语
以上流程写的比较糙,各位有疑问的地方,欢迎留言和探讨