现在接触的项目是公司的路由中台,每天的数据量是亿级别的,同时要记录每一次请求的详细数据
开始的时候这些记录数据是存放到elasticsearch与DB2数据库中各自保存
当需要查询某个路由信息的详情时从ES中获取,速度非常快,当想获取统计报表的时候从DB2中统计,本来是相安无事的,ES速度快,DB2是关系型数据库,易于统计分析
但是因为公司要放弃DB2数据库,所以做统计分析的SQL语句也就没用了,需要从ES中获取数据并统计分析
这个时候问题就出现了,较为复杂的SQL语句如何转变为DSL语句
如何分组?如何关联?如何子查询
关于基本SQL如何转变为DSL语句,大家可以参考这个网站http://www.atotoa.com/,同时还有一些开源框架,这里我没有使用,公司这边纯内网开发,找不到那种东西就没用,java端使用的是highlevelclient
目前这些转变中已经做到了分组和聚合的对应,但是其中也有一些细节需要拿出来说一说
一:group by和aggs的区别
SQL语句分组查出来的数据仍然是扁平的数据,最终还是能得到一个List<T> ,但是DSL通过Aggs聚合得到的数据是有深度的,一层套一层,如果想获取到SQL那种数据结构,理论上来说聚几次就需要几层循环一层层的取.
在公司项目改造中,为了取出数据使用了7层循环去取数据
二:也许有的sql还不止7层,使用7层妖塔似乎有点渗人,其他方法有没有呢
确实可以将聚合拆分,可以每次aggs一次,但是在拿到这些数据时,需要对聚合7次获取的数据设计一个算法,通过这种方式获取到数据有问题,最终放弃了(其实这是一个很好的思路,7次聚合带来的压力如果分成7个单一聚合,ES服务会非常安全)
三:聚合7次带来的服务器压力
公司每日的数据都存入一个新的index,测试库2000W数据 将近60G 大小,而生产库每天亿级数据,这么大量的数据进行7次聚合,最终会直接让服务器崩溃
多次测试发现多次聚合都导致了测试ES崩溃,虽然生产服务器更强大,但是这样肯定不行
四:使用query_match代替聚合
如果要进行两次聚合,比如下面的语句
实际上也可以使用
将聚合条件转变为query条件,让聚合次数降低,单次查询数量级下降
比如在我的生产库中有2E跳数据,我使用的query字段有1000个值,那么每次聚合的数据就是2E/1000=20W
把一次查询ES 2E的数据量变为查询1000次ES每次查20W的数据量
java代码虽然复杂了点,但是完全值得