OLAP技术之Kylin官方案例详细剖析-商业环境实战

本套系列博客从真实商业环境抽取案例进行总结和分享,并给出Spark源码解读及商业实战指导,请持续关注本套博客。版权声明:本套Spark源码解读及商业实战归作者所有,禁止转载,欢迎学习。

Kylin官方案例是一个订单案例,其中包含了订单事实表,订单日期表,商品分类维度,账号维度(购买者和销售者)以及区域维度(购买者和销售者)

一:表关系

KYLIN_SALES(事实表)
KYLIN_CAL_DT(时间维度)--> KYLIN_SALES            KYLIN_SALES.PART_DT = KYLIN_CAL_DT.CAL_DT
KYLIN_CATEGORY_GROUPING(商品类别)  --> KYLIN_SALES KYLIN_SALES.LEAF_CATEG_ID =KYLIN_CATEGORY_GROUPINGS.LEAF_CATEG_ID
                                                  KYLIN_SALES.LSTG_SITE_ID = KYLIN_CATEGORY_GROUPINGS.SITE_ID
                                                  
KYLIN_ACCOUNT(购买账号)--> KYLIN_SALES           KYLIN_SALES.BUYER_ID = KYLIN_ACCOUNT.ACCOUNT_ID
KYLIN_ACCOUNT(卖出账号)--> KYLIN_SALES           KYLIN_SALES.SELLER_ID = KYLIN_ACCOUNT.ACCOUNT_ID

KYLIN_COUNTRY  --> KYLIN_ACCOUNT (购买账号)      KYLIN_ACCOUNT.ACCOUNT_COUNTRY = KYLIN_COUNTRY.COUNTRY
KYLIN_COUNTRY  --> KYLIN_ACCOUNT (卖出账号)      KYLIN_ACCOUNT.ACCOUNT_COUNTRY = KYLIN_COUNTRY.COUNTRY
复制代码

二:建立模型

1:Kylin 官方模型 model关系图如下:

2:模型建设第一步,雪花和星型模型,建立inner join关系,重要的是确定字段关联,对于角色维度(KYLIN_ACCOUNT和KYLIN_COUNTRY),需要别名处理。

该处Snapshot Table 总结的很好,所以标明引用地址: juejin.im/post/5bcf37…

对 “Add Lookup Table” 页面的几点说明:

  1. 数据关系不仅仅是事实表与维度表之间(星型模型),维度表和维度表之间(雪花模型)也可以建立联系;
  2. 表与表之间的连接添加有三种:“Left Join”、“Inner Join”、“Right Join”;
  3. Skip snapshot for this lookup table 选项指的是是否跳过生成 snapshotTable,由于某些 Lookup 表特别大(大于 300M),如果某一个维度的基数比较大 ,可能会导致内存出现 OOM,所以在创建 snapshotTable 的时候会限制原始表的大小不能超过配置的一个上限值(kylin.snapshot.max-mb,默认值300);
  4. 跳过构建 snapshot 的 lookup 表将不能搜索,同时不支持设置为衍生维度(Derived);
  5. 大部分情况下都是使用 “Left Join”,其他两种 Join 方式不是很常用。

3:模型建设第二步,维度选择:

在 Dimensions 页面选择可能参与计算的维度,这里被选择的只是在 Cube 构建的时候拥有被选择资格的维度,并不是最后参与 Cube 构建的维度,推荐将维度表中的字段都选择上。 如下展示了Dimensions的选择:

 对于KYLIN_SALES,其中SLR_SEGMENT_CD,PRICE,ITEM_COUNT没有选择,所以没有资格参与cubeId构建

 对于KYLIN_CAL_DT,其中仅选择了部分参与的维度,其他没有资格参与cubeId构建

 对于KYLIN_CATEGORY_GROUPING,其中仅选择了部分参与的维度,其他没有资格参与cubeId构建

 对于BUYER_ACCOUNT 与 SELLER_ACCOUNT,全部有资格参与cubeId构建

 对于BUYER_COUNTRY,只有COUNTRY , NAME 有资格参与cubeId构建

 对于SELLER_COUNTRY,只有COUNTRY , NAME 有资格参与cubeId构建

同理如上

最终维度选择结果:

4: Measures度量指标选择:

在 Measures 页面选择可能用于计算的度量。一般而言,销售额、流量、温湿度等会作为度量。

5、Settings设置

在 Settings 页面可以设置分区以及过滤条件,其中分区是为了系统可以进行增量构建而设计的,目前 Kylin 支持基于日期的分区,在 “Partition Date Column” 后面选择事实表或者维度表中的日期字段,然后选择日期格式即可;过滤条件设置后,Kylin 在构建的时候会选择符合过滤条件的数据进行构建。 需要注意的几点:

  1. 时间分区列可以支持日期或更细粒度的时间分区;
  2. 时间分区列支持的数据类型有 time/date/datetime/integer等;
  3. 过滤条件不需要写 WHERE;
  4. 过滤条件不能包含日期维度。

6、模型总结

该处Snapshot Table 总结的很好,所以标明引用地址: juejin.im/post/5bcf37…

每一个 Snapshot 是和一个 Hive 维度表对应的,生成的过程是:

  • 从原始的hive维度表中顺序得读取每一行每一列的值;
  • 使用 TrieDictionary 方式对这些所有的值进行编码(一个值对应一个 Id);
  • 再次读取原始表中每一行的值,将每一列的值使用编码之后的 Id 进行替换,得到了一个只有 Id 的新表;
  • 同时保存这个新表和 Dictionary 对象(Id 和值的映射关系)就能够保存整个维度表;
  • Kylin 将这个数据存储到元数据库中。

三:建立cube

1:维度剪枝优化

在选择维度时,每一个维度列可以作为普通维度(Normal),也可以作为衍生维度(Derived)。相对于普通维度来说,衍生维度并不参与维度的 Cuboid,衍生维度对应的外键(FK)参与维度 Cuboid,从而降低 Cuboid 数。在查询时,对衍生维度的查询会首先转换为对外键所在维度的查询,因此会牺牲少量性能(大部分情况下可以接受)。 1:维度剪枝优化 在一个多维数据集合中,维度的个数决定着维度之间可能的组合数,而每一个维度中成员集合的大小决定着每一个可能的组合的个数,例如有三个普通的维度A、B、C,他们的不同成员数分别为10/100/1000,那么一个维度的组合有2的3次方个,分别是{空、A、B、C、AB、BC、AC、ABC},每一个成员我们称为cuboid(维度的组合),而这些集合的成员组合个数分别为1、10、100、1000、10*100、100 1000、101000和10 *100 *1000。我们称每一个dimension中不同成员个数为cardinatily,我们要尽量避免存储cardinatily比较高的维度的组合。

在上面的例子中我们可以不缓存BC和C这两个cuboid,可以通过计算的方式通过ABC中成员的值计算出BC或者C中某个成员组合的值,这相当于是时间和空间的一个权衡吧。在kylin中存在的四种维度是为了减少cuboid的个数,而不是每一个维度是否缓存的,当前kylin是对所有的cuboid中的所有组合都进行计算和存储的,对于普通的dimension,从上面的例子中可以看出N个维度的cuboid个数为2的N次方,而kylin中设置了一些维度可以减少cuboid个数,当然,这需要使用者对自己需要的维度十分了解,知道自己可能根据什么进行group by。

1.1、Mandatory维度

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

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

1.2、hierarchy维度

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

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

1.3、derived维度

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

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

1.4. 粒度优化

粒度优化对应的是提高Cube的并发度,其设置是在自定义属性中的 一共有三个属性可以提高并发度。 1.kylin.hbase.region.cut(共使用几个分区) 2.kylin.hbase.region.count.min(最少使用几个分区) 3.kylin.hbase.region.count.max(最多使用几个分区)

根据相对应的情况调高最少使用分区,降低最大使用分区,能够有效增加系统的并行度。

1.5. RowKey优化

写的非常好,参考链接:juejin.im/post/5bd5c5…

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 类型。

  • 和Hbase 的RowKey优化类似,在查询的过程中,被用作过滤条件的维度可能放在其他维度的前面,经常出现的维度应该放在前面,基数比较大的维度应该放在前面

猜你喜欢

转载自juejin.im/post/5bd7c6f3e51d45723552d5c4