写点什么

大数据 -165 Apache Kylin Cube7 实战:聚合组 /RowKey/ 编码与体积精度对比

作者:武子康
  • 2025-11-27
    山东
  • 本文字数:3703 字

    阅读完需:约 12 分钟

大数据-165 Apache Kylin Cube7 实战:聚合组/RowKey/编码与体积精度对比

TL;DR

  • 场景:由 Cube4 克隆出 Cube7(维度均为 Normal),对比体积、精度,并梳理聚合组与 RowKey 实操要点。

  • 结论:在同等数据量下,维度数↑→ Cuboid 指数级↑→ 存储与构建成本显著↑;用聚合组 + Mandatory/Hierarchy/Joint 可控复杂度。

  • 产出:实测 size & CubeStatsReader 结果、RowKey/编码/ShardBy 的工程化建议与常见错误速查卡。


版本矩阵


定义 Cube7

省略 Model 等操作。构建前面 Cube4 类似的 Cube7,仅在维度定义有区别。(我这里是 Clone Cube4,然后修改的)wzk_test_kylin_cube_7 的字段中,都是 Normal:



生成的如下图:


构建 Cube7

大小对比

查看 Size 的对比:由于之前数据太多跑的太慢,我的 cube-4 是 125 条数据占用 22KB,我的 cube-7 是 15 条占用 9KB。



粗略可以估计出来,cube-7 的大小要比 cube-4 的大小大很多(如果同数据量的话)

精度对比

wzk_kylin_test_cube_4

kylin.sh org.apache.kylin.engine.mr.common.CubeStatsReader wzk_kylin_test_cube_4
复制代码


对应的信息如下:


wzk_kylin_test_cube_7

kylin.sh org.apache.kylin.engine.mr.common.CubeStatsReader wzk_kylin_test_cube_7
复制代码


对应的信息如下:


聚合组

随着维度数目的增加,Cuboid 的数量会爆炸式的增长,为了缓解 Cube 的构建压力,Apache Kylin 引入了一系列高级的设置,帮助用户筛选出真正需要的 Cuboid(本质是要减少 Cube 构建过程中的预计算),这些高级设置包括:


  • 聚合组(Aggregation Group)

  • 强制维度(Mandatory Dimension)

  • 层级维度(Hierachy Dimension)

  • 联合维度(Joint Dimension)



默认 Kylin 会把所有维度放在同一个聚合组中如果维度数较多(如维度数>15),建议用户根据查询的习惯和模式,将维度分布到多个聚合组中。通过使用多个聚合组,可以大大降低 Cube 中的 Cuboid 数量。如一个 Cube 有(M+N)个维度:


  • 这些维度放在一个聚合组中,默认有 2^(M+N)个 Cuboid

  • 将这些维度分为两个不相交的聚合组,第一个组有 M 个维度,第二个组有 N 个维度。那么 Cuboid 的总数为(2^M + 2^N)个维度

  • 一个维度可以出现在多个聚合组中


在单个组合组中,可以对维度设置一些高级属性,包括强制思维、层级维度、联合维度。一个维度只能出现在一个属性组中。构建 N 个维度的 Cube 会生成的 2^N 个 Cuboid,如下图所示,构建一个 4 个维度(A、B、C、D)的 Cube,需要生成 16 个 Cuboid。



根据用户关注的维度组合,可以维度划分不同的组合类,这些组合类在 Kylin 中被称为聚合组,如用户仅仅关注维度 AB 组合和维度 CD 组合,那么该 Cube 则可以被分化成两个聚合组,分别是聚合组 AB 和聚合组 CD。生成的 Cuboid 数目从 16 个缩减为 8 个。



用户关心的聚合组之间可能包含相同的维度,如聚合组 ABC 和聚合组 BCD 都包含维度 B 和维度 C,这些聚合组之间会衍生相同的 Cuboid。聚合组 ABC 会产生 Cuboid BC,聚合组 BCD 也会产生 Cuboid BC。这些 Cuboid 不会重复生成,一份 Cuboid 为这些聚合组所共有。



有了聚合组就可以粗粒度的对 Cuboid 进行筛选,获取自己想要的维度组合。Kylin 的建模需要业务专家参数。

强制维度(Mandatory Dimension)

强制/必要 维度:指的是那些总会出现在 Where 条件或 Group By 语句中的维度。通过指定某些维度为强制维度,Kylin 不预计算那些不包含此维度的 Cuboid,从而减少计算量。维度 A 是强制维度,那么生成的 Cube 如下图所示,维度数从 16 变成 9。


层级维度(Hierachy Dimension)

层级维度:是指一组有层级关系的维度维度中常常会出现具有层级关系的维度,例如:国家、省份、城市这三个维度,从上而下来说:国家/省份/城市之间分别是一对多的关系。假设维度 A 代表国家,维度 B 代表省份,维度 C 代表城市,ABC 三个维度可以被设置为层级维度,生成的 Cube 如下图所示:



Cuboid[A,C,D] = Cuboid[A,B,C,D], Cuboid[B,D] = Cuboid[A,B,D],因而 Cuboid[A,C,D] 和 Cuboid[B,D] 就不必重复存储。

联合维度(Joint Dimension)

联合维度:是将多个维度视作一个维度,在进行组合计算的时候,它们要么一起出现,要么均不出现。通常适用于以下几种情形:


  • 总是在一起查询的维度

  • 彼此之间有一定映射关系,如 USER_ID 和 EMAIL

  • 基数很低的维度,如性别、布尔类型的属性


维度的基数:维度有多少个不同的值。联合维度并不关心维度之间各种细节的组合方式,如用户查询语句中仅仅会出现 GROUP BY A,B,C,而不会出现 GROUP BY A、B 或者 GROUP BY C 等等这细化的维度组合。这一类问题就是联合维度所解决的问题。


例如将 A、B、C 定义为联合维度,Apache Kylin 就仅仅构建 Cuboid ABC,而 Cuboid AB、BC、A 等等 Cuboid 都不会被生成,最终 Cube 结果如下图所示的,Cuboid 数目从 16 减少到 4:


总结内容

  • 在单个聚合组中,可以对维度进行设置,包括强制维度、层级维度、联合维度。

  • 强制维度:指的是那些总会出现在 Where 条件或者 GROUP BY 子句中的维度

  • 层级维度:一组具有层级关系的维度(如:国家、省、市)

  • 联合维度:将多个维度看成一个角度,要么一起出现,要么都不出现

RowKeys

简单的说 Cuboid 的维度会映射为 HBase 的 Rowkey,Cuboid 的指标会映射为 HBase 的 Value。



  • 如上图原始表所示:Hive 表有两个维度列 year、city,有一个指标列 price。

  • 如上图预聚合表所示:我们具体要计算的是 year 和 city 这两个维度所有维度组合(即 4 个 cuboid)下的 sum(prices)指标,这个指标的具体计算过程就由 MapReduce 完成的。

  • 如上图的字典编码所示:为了节省存储资源,Kylin 对维度值进行了字典编码,图中将 beijing 和 shanghai 依次编码 0 和 1。

  • 如上图 HBase KV 存储所示:在计算 Cuboid 过程中,会将 Hive 表的数据转换为 HBase 的 KV 形式。Rowkey 的具体格式是 Cuboid id + 具体的维度值(最新的 Rowkey 中为了并发查询还加入了 Shard Key),以预聚合表内容的第 2 行为列,其维度组合是(year,city),所以 Cuboid id 就是 00000011,Cuboid 是 8 位,具体维度值是 1994 和 shanghai,所以编码后的维度值对应上图的字典编码也是 11,所以 HBase 的 Rowkey 就是 00000011,对应 HBase Value 就是 sum(price)的具体值。

  • 所有的 Cuboid 计算完成后,会将 Cuboid 转换为 HBase 的 KeyValue 格式生成 HBase 的 HFile,最后将 HFile Load 进 Cube 对应的 HBase 表中。


编码

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


  • Dictionary 字典编码将所有此维度下的值构成一张映射表,从而大大节约存储空间,适用于大部分字段,默认推荐使用。Dictionary 产生的编码非常紧凑,尤其在维度的值基数小且长度大的情况下,但在超高基情况下,可能引起内存不足的问题,在 Kylin 中字典编码允许的基数上限默认是 500 万(由参数 kylin.dictionay.max.cardinality 配置)

  • boolean:适用于字段为:ture、false、TURE、FALSE、t、f、T、F、yes、no、YES、NO、y、n、Y、N、1、0

  • date:适用于字段为日期字符,支持的格式包括 yyyyMMdd、yyyy-MM-dd、yyyy-MM-dd HH:mm:ss.SSS

  • time:适用于字段为时间戳字符,支持范围为[1970-01-01 00:00:00],[2038-01-09 03:14:07],毫秒部分会被忽略,time 编码适用于 time、datetime、timestamp 等类型

  • fix_length:使用超高基环境,将选取字段的前 N 个字节为编码值,当 N 小于字段长度,会造成字段阶段,当 N 较大时,造成 RowKey 过长,查询性能下降,只适用于 varchar、nvarchar 类型

  • fixed_length_hex:适用于字段为十六进制字符,比如 1A2BFF 或者 FF00FF,每两个字符需要一个字节,只适用于 varchar 或 nvarchar 类型

顺序

各维度在 RowKeys 中的顺序,对于查询的性能会产生较明显的影响,在这里用户可以根据查询的模式和习惯,通过拖拽的方式调整各个维度在 RowKeys 上的顺序,推荐的顺序为:


  • Mandatory 维度

  • where 过滤条件中出现频率较多的维度

  • 高基数维度

  • 低基数维度放后面

  • 不常用的维度放在后面这样做的好处是,充分利用过滤条件来缩小在 HBase 中扫描的范围,从而提高查询的效率。

分片

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

错误速查

其他系列

🚀 AI 篇持续更新中(长期更新)

AI 炼丹日志-29 - 字节跳动 DeerFlow 深度研究框斜体样式架 私有部署 测试上手 架构研究,持续打造实用 AI 工具指南!AI 研究-127 Qwen2.5-Omni 深解:Thinker-Talker 双核、TMRoPE 与流式语音🔗 AI模块直达链接

💻 Java 篇持续更新中(长期更新)

Java-174 FastFDS 从单机到分布式文件存储:实战与架构取舍 MyBatis 已完结,Spring 已完结,Nginx 已完结,Tomcat 已完结,分布式服务已完结,Dubbo 已完结,MySQL 已完结,MongoDB 已完结,Neo4j 已完结,FastDFS 正在更新,深入浅出助你打牢基础!🔗 Java模块直达链接

📊 大数据板块已完成多项干货更新(300 篇):

包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈!大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT 案例 详解🔗 大数据模块直达链接

发布于: 刚刚阅读数: 3
用户头像

武子康

关注

永远好奇 无限进步 2019-04-14 加入

Hi, I'm Zikang,好奇心驱动的探索者 | INTJ / INFJ 我热爱探索一切值得深究的事物。对技术、成长、效率、认知、人生有着持续的好奇心和行动力。 坚信「飞轮效应」,相信每一次微小的积累,终将带来深远的改变。

评论

发布
暂无评论
大数据-165 Apache Kylin Cube7 实战:聚合组/RowKey/编码与体积精度对比_Java_武子康_InfoQ写作社区