Kylin实战:建立cube的优化

时间:2024-04-04 10:30:23

目录

背景

Kylin的维度组合优化

1、 Mandatory维度

2、 hierarchy维度

3、 derived维度

4、 联合维度

Kylin的Rowkey优化

1、编码

2、顺序

3、分片


背景

了解OLAP Cube的人都会知道,建立cube的过程中往往会出现“维度爆炸”问题。Kylin是典型的Multidimensional OLAP应用,牺牲灵活性,使用预计算来提升性能,以实现对超大数据集的秒级响应。在Kylin建立cube的过程中,如果默认选择所有维度的组合,那么维度组合将是2^N(N为维度个数)。

在工业领域,一般建立的宽表可能会有大几十个的维度,甚至达到上百。但是平常使用的时候,也许只有不到一半的维度组合能超过20个维度。大部分维度组合的个数可能都是10多个。这样一来,会造成存储的极大浪费,也会影响Kylin的查询性能。

Kylin的维度组合优化

kylin从1.5版本后引入了一个新的特性:聚合组(Aggregation Groups)。

 

如下是官网提出的两种方法:

1、首先,我们可以移除那些不一定是维度的维度。例如,假设有一个日期查找表,其中保存的cal_dt是PK列,以及许多派生列,如week_begin_dt、month_begin_dt。尽管分析人员需要week_begin_dt作为维度,但我们可以对它进行删减,因为它总是可以从维度cal_dt中计算出来,这就是“派生”优化。

 

2、其次,可以修剪聚合组之间的某些组合。这是本文的主要讨论,我们称之为“组合修剪”。例如,如果将某个维度指定为“强制”,则可以删除所有没有该维度的组合。如果维A,B,C形成“层次”关系,则仅保留与A,AB或ABC的组合。在v1.5之前,Kylin还具有“聚合组”概念,该概念也可用于组合修剪。但是,它的文献记录不多,很难理解(我也发现很难解释)。无论如何,我们将跳过它,因为我们将重新定义“聚合组”的真正含义。

 

下文主要讲解第二种方法-----维度剪枝优化:

在kylin1.5之后,有四种类型的聚合组,每一种类型的聚合组也即是一种特定的规则。通过这四种规则来达到剪枝优化的目的。

 

1、 Mandatory维度

这种维度意味着每次查询的group by中都会携带的,将某一个dimension设置为mandatory可以将cuboid的个数减少一半,如下图:

Kylin实战:建立cube的优化

 

这是因为我们确定每一次group by都会携带A,那么就可以省去所有不包含A这个维度的cuboid了。

2、 hierarchy维度

这种维度是最常见的,尤其是在mondrian中,我们对于多维数据的操作经常会有上卷下钻之类的操作,这也就需要要求维度之间有层级关系,例如国家、省、城市,年、季度、月等。有层级关系的维度也可以大大减少cuboid的个数。如下图:

Kylin实战:建立cube的优化

 

这里仅仅局限于A/B/C是一个层级,例如A是年份,B是季度、C是月份,那么查询的时候可能的组合只有年、xx年的季度、xx年xx季度的xx月,这就意味着我们不能再单独的对季度和月份进行聚合了,例如我们查询的时候不能使用group by month,而必须使用group by year,quart,month。如果需要单独的对month进行聚合,那么还需要再使用month列定义一个单独的普通维度。

3、 derived维度

这类维度的意思是可推导的维度,需要该维度对应的一个或者多个列可以和维度表的主键是一对一的,这种维度可以大大减少cuboid个数,如下图:

Kylin实战:建立cube的优化

例如timeid是时间这个维度表的主键,也就是事实表的外键,时间只精确到天,那么year、month、day三列可以唯一对应着一个time_id,而time_id是事实表的外键,那么我们可以指定year、month、day为一个derived维度,实际存储的时候可以只根据timeid的取值决定维度的组合,但这就要求我们在查询的时候使用的group by必须指定derived维度集合中的所有列。 3.联合维度(Joint) 每一个联合维度包括两个或者更多的维度,联合维度内的维度,要么不出现,要么必须一起出现。不同的联合之间不应当有共同的维度

4、 联合维度

联合维度:将几个维度视为一个维度。 适用场景:

  • 1 可以将确定在查询时一定会同时使用的几个维度设为一个联合维度。
  • 2 可以将基数很小的几个维度设为一个联合维度。
  • 3 可以将查询时很少使用的几个维度设为一个联合维度。

优化效果:将N个维度设置为联合维度,则这N个维度组合成的cuboid个数会从2的N次方减少到1。

应用实例:

假设创建一个交易数据的Cube,它具有很多普通的维度,像是交易日期 cal_dt,交易的城市 city,顾客性别 sex_id 和支付类型 pay_type 等。分析师常用的分析方法为通过按照交易时间、交易地点和顾客性别来聚合,获取不同城市男女顾客间不同的消费偏好,例如同时聚合交易日期 cal_dt、交易的城市 city 和顾客性别 sex_id来分组。 聚合组:[cal_dt, city, sex_id,pay_type] 联合维度: [cal_dt, city, sex_id]

Case 1:

SELECT cal_dt, city, sex_id, count(*) FROM table GROUP BY cal_dt, city, sex_id
则它将从Cuboid [cal_dt, city, sex_id]中获取数据
复制代码

Case2:

如果有一条不常用的查询:

 SELECT cal_dt, city, count(*) FROM table GROUP BY cal_dt, city
 则没有现成的完全匹配的 Cuboid,Apache Kylin 会通过在线计算的方式,从现有的 Cuboid 中计算出最终结果。

 

Kylin的Rowkey优化

1、编码

Kylin 以 Key-Value 的方式将 Cube 存储到 HBase 中,HBase 的 key,也就是 Rowkey,是由各维度的值拼接而成的;为了更高效地存储这些值,Kylin 会对它们进行编码和压缩;每个维度均可以选择合适的编码(Encoding)方式,默认采用的是字典(Dictionary)编码技术;字段支持的基本编码类型如下:

  • dict:适用于大部分字段,默认推荐使用,但在超高基情况下,可能引起内存不足的问题;
  • boolean:适用于字段值为true, false, TRUE, FALSE, True, False, t, f, T, F, yes, no, YES, NO, Yes, No, y, n, Y, N, 1, 0;
  • integer:适用于字段值为整数字符,支持的整数区间为[ -2^(8N-1), 2^(8N-1)];
  • date:适用于字段值为日期字符,支持的格式包括yyyyMMdd、yyyy-MM-dd、yyyy-MM-dd HH:mm:ss、yyyy-MM-dd HH:mm:ss.SSS,其中如果包含时间戳部分会被截断;
  • time:适用于字段值为时间戳字符,支持范围为[ 1970-01-01 00:00:00, 2038/01/19 03:14:07],毫秒部分会被忽略,time编码适用于 time, datetime, timestamp 等类型;
  • fix_length:适用于超高基场景,将选取字段的前 N 个字节作为编码值,当 N 小于字段长度,会造成字段截断,当 N 较大时,造成 RowKey 过长,查询性能下降,只适用于 varchar 或 nvarchar 类型;
  • fixed_length_hex:适用于字段值为十六进制字符,比如 1A2BFF 或者 FF00FF,每两个字符需要一个字节,只适用于 varchar 或 nvarchar 类型。

2、顺序

各维度在 Rowkeys 中的顺序,对于查询的性能会产生较明显的影响;在这里用户可以根据查询的模式和习惯,通过拖曳的方式调整各个维度在Rowkeys上的顺序。推荐的顺序为:Mandatory 维度、where 过滤条件中出现频率较多的维度、高基数维度、低基数维度。这样做的好处是,充分利用过滤条件来缩小在 HBase 中扫描的范围,从而提高查询的效率。

3、分片

指定 ShardBy 的列,明细数据将按照该列的值分片;没有指定 ShardBy 的列,则默认将根据所有列中的数据进行分片;选择适当的 ShardBy 列,可以使明细数据较为均匀的分散在多个数据片上,提高并行性,进而获得更理想的查询效率;建议选择基数较大的列作为 ShardBy 列,以避免数据分散不均匀

 

 

 

参考:

1、http://kylin.apache.org/blog/2016/02/18/new-aggregation-group/

2、https://juejin.im/post/5bd81eafe51d457b26679917#heading-25

3、https://juejin.im/post/5bd5c59851882565e031f4be#heading-17