栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

使用sql来替换elasticsearch的PipelineAggregatorBuilders.bucketSelector()

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

使用sql来替换elasticsearch的PipelineAggregatorBuilders.bucketSelector()

前言

22届java来公司,刚好遇到公司技术栈升级换代。二话不说上来就是把公司骨灰级代码搬出来,然后选其中一个子系统交给我让我改。别说摸着石头过河了,这边这个开发部刚成立,就一个老员工还不是很熟悉es,我直接自己开路!
期间,这老代码基本没注释,唯一看到的只有三行看到一些前辈在代码中气的吐血写下的一些骂人的注释,起初年少轻狂,不以为意,后来改到那个地方了才知道,前辈骂的对啊!就比如这个破PipelineAggregatorBuilders.bucketSelector(),要把它用sql替换了。里面定义的一些变量,真是惨无人道!

解决方案

在网上查了好久没有查到合适的解决方法。后来无意间看到网上说PipelineAggregatorBuilders.bucketSelector()相当于聚合后的having,然后恍然大悟,困扰我两周的问题算是有了头绪。再看,公司的业务比较复杂,这个方法所在的业务里es嵌套聚合了三层。其中用了它两层。然后,由于嵌套的厉害,业务需求也没有什么可参考的,唯一的就是从老代码中参悟玄机,这里我一度陷入了逻辑死角,总觉得改不出来。后来,另辟蹊径,尝试着理解业务场景,明白es写的老代码是要做什么,然后需要怎么改,就这样慢慢地推演出了符合业务场景的sql,把这个问题给解决了。

模拟业务场景
  • 假设业务需求是:商店里有台智能设备,它可以识别每个用户,记录每个用户每次在商店里购物的时间以及花费的金额。现在,商店的负责人需要找出商店的大金主(即经常大额消费的顾客),准备向这些大金主下发VIP购物卡,以此来增加这些大金主的粘性,避免流失。(即寻找出一周(7天))内消费1000元的顾客。

先看es的写法,没错,就是这么套娃。

List aggregationList = new ArrayList<>();
		TermsAggregationBuilder userBuilder = AggregationBuilders.terms(UserDao.NAME+"Agg").field(UserDao.NAME).size(Integer.MAX_VALUE);
		DateHistogramAggregationBuilder timeBuilder = AggregationBuilders.dateHistogram(UserDao.TIME+"Agg").field(UserDao.TIME).dateHistogramInterval(DateHistogramInterval.DAY).format("yyyyMMdd").offset("+8h");
		timeBuilder.subAggregation(AggregationBuilders.sum(UserDao.MONEY+"Agg").field(UserDao.MONEY));
timeBuilder.subAggregation(PipelineAggregatorBuilders.bucketSelector("user_money", new Script("params._value0 > 1000"), UserDao.MONEY+"Agg"));	userBuilder.subAggregation(PipelineAggregatorBuilders.bucketSelector("user_time", new Script("params._value0 >= 7"), UserDao.TIME+"Agg._bucket_count"));
		
		userBuilder.subAggregation(timeBuilder);
		aggregationList.add(userBuilder);

在改sql之前要搞清楚,es中桶聚合相当于是group by 不过它还是有些不太一样。它的那个bucket桶有一个类似于count的属性,可以方便地统计每个桶中有多少文档。而如果是sql,除了嵌套sql之外,我们不能够计算出每个字段group by分组之后的count。但是,注意下,这里的管道查询的桶选择器,由于它的存在,相当于把嵌套sql直接给干死。然后只能多字段分组查询。然而多字段分组查询,这样我们就不能像es那样,得到每个桶聚合后的count了,因此这里我一度陷入了坑里,久久爬不出来。后来,一遍一遍分析代码从查询的结果中拿到的是什么数据,而它又想干什么。慢慢弄清楚业务场景,然后才发觉,这个count在这里我是不需要的分组统计的,我最终需要的是user。分析清楚后,我把思绪整理整理,最终拼接sql如下:

select name as nameAgg,time as timeAgg,count(time) as timeCount sum(money) as moneyAgg  from usertable  where ...一些条件 group by name,time having timeCount >= 7 and moneyAgg > 1000;
总结

最后,我想说,当遇到问题时,不要抱怨,不要害怕。首先去网上搜,搜不到的去官网,es中好多复杂的查询以及业务场景,网上很少涉及。有些大部分都是简单入个门,真正复杂的需要我们去官网查,结合业务场景推理业务逻辑。搞清楚时,再下手去做。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1035643.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号