维度诅咒,是所有预计算OLAP引擎的严重问题;
在1.5之前, kylin使用一些简单的技术处理这个问题,也减轻了问题的严重程度;
在开源实践过程中,我们发现这些技术缺乏系统性设计思维,也无法处理很多常见问题;
在1.5,我们重新设计了聚合组(aggregation group)机制,以更好地适应所有类型的cube设计场景;
已知的是,Kylin通过预计算"cube集"加快查询速度,意味着包含所有维度的不同组合,也就是"cuboid集";
产生的问题就是,随着维度(dimension)的增长,cuboid集会指数级增长;
举个例子,3个维度时cube会有8个cuboid,4个维度时就有16个cuboid(2^N);
即使Kylin使用可扩展的计算框架(MapReduce)和存储(HBase)来计算和存储cube集,如果cube大小几倍于原始数据也是不能接受的;
解决方案是裁剪不需要的维度.在优化cube设计里讨论过的,有两种方式:
第一个方式是:移除不需要的维度.
例如,假设有一张日期查找表,cal_dt字段为主键,衍生出其他字段如week_begin_dt, month_begin_dt.即使查询时需要week_begin_dt字段(即:维度),也可以从字段cal_dt计算出来,所以可以裁剪week_begin_dt字段,这称为衍生优化(“derived” optimization);
如Kylin示例的kylin_cal_dt表:
cal_dt | year_beg_dt | month_beg_dt | week_beg_dt |
---|---|---|---|
2012-08-16 | 2012-01-01 | 2012-08-01 | 2012-08-11 |
2012-01-03 | 2012-01-01 | 2012-01-01 | 2012-01-01 |
第二个方式是:维度集中的一些组合可以裁剪.这是本章讨论的重点,称为"维度组合裁剪".
例如,一个维度定义为"必要的",所有没有包含这个维度的维度组合,都可以裁剪.
如果维度A,B,C构成"层级关系",维度组合A,AB或ABC会保留下来.
1.5之前,Kylin也有"聚合组"的概念,也用于维度组合裁剪.但是有很少的文档,很难理解.所以会跳过1.5,重新定义"聚合组".
原先维度组合裁剪技术的缺点:1,这些技术是各自独立的,没有系统性;2,没有良好设计和文档化,很难外部使用;3,没有足够多的描述语义(describing semantics);
为了说明描述语义的问题,假设一个数据cube,有一个高基数维度buyer_id,以及一些正常的维度如日期cal_dt,buyer所在的城市等.
一个分析需要按非buyer_id维度分组以获得全局印象,如以cal_dt分组.分析也需要下钻,检查指定的buyer的行为,按buyer_id过滤;而buyer_id具有高基数性,一旦buyer_id确定了,相关的记录就会很少.在这个例子中,预期的裁剪策略的输出为:
Cuboid | 计算 或 跳过 | 理由 |
---|---|---|
city | 计算 | 支持 以城市分组 的查询 |
cal_dt | 计算 | 支持 以日期分组 的查询 |
buyer_id | 跳过 | 以buyer分组,会产生大量的结果,buyer_id应该用于在基本cuboid里查询时做为过滤条件 |
city,cal_dt | 计算 | 支持 以城市和日期分组 的查询 |
city,buyer_id | 跳过 | 以buyer分组,会产生大量的结果,buyer_id应该用于在基本cuboid里查询时做为过滤条件 |
cal_dt,buyer_id | 跳过 | 以buyer分组,会产生大量的结果,buyer_id应该用于在基本cuboid里查询时做为过滤条件 |
city,cal_dt,buyer_id | 计算 | 基本cuboid |
在Kylin 1.5之前,没有设置裁剪策略的语义工具;
在Kylin 1.5,我们重新设计了聚合组机制.参见Kylin Cuboid Whitelist,新设计允许cube设计者定义预期的cuboid集白名单;
新设计中,"聚合组"定义为cuboid集的集群,并提供分片规则.Cube设计者可以为一个cube定义多个聚合组,所有包含有效"维度组合"的聚合组集合并为cube提供cuboid集;注意,一个cuboid可以出现在多个聚合组里,并且在构建cube时只会计算一次;
在聚合组的源码里,有两个重要的属性定义:@JsonProperty("includes")
和@JsonProperty("select_rule")
@JsonProperty("includes")
: 定义聚合组里包含哪些维度;值必须是全部维度的子集;只包含必要的维度,以使列表最小;
@JsonProperty("includes")
:聚合组集中有效的cuboid集的选取规则.cube设计者可以定义多条规则应用于所包含的维度,当前有三类的规则:
Kylin的cuboid计算周期器(scheduler),会基于定义的聚合组来安排有效cuboid的计算顺序.你不用关心具体实现,因为每个cuboid只会计算一次.唯一要关心的是:不要滥用聚合组.多应用聚合组的选取规则,避免引使用大理的单cuboid聚合组,除非有必要.过多的聚合组是cuboid计算周期器的负担,对查询引擎也一样;
有了新的聚合组这个工具,buyer_id问题可以这样解决,cube可以定义两个聚合组:
聚合组1只用于基本cuboid;聚合组2将应用所有没有buyer_id的cuboid集;