写点什么

大数据 -162 Apache Kylin 增量 Cube 与 Segment 实战:按天分区增量构建指南

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

    阅读完需:约 11 分钟

大数据-162 Apache Kylin 增量 Cube 与 Segment 实战:按天分区增量构建指南

TL;DR

  • 场景:Hive 表每天追加数据,历史量大,不想重复全量构建。

  • 结论:以分区列作为分割时间列,按天构建多 Segment;查询会多一次运行时聚合但可控。

  • 产出:分区建表+增量构建流程+查询验证+常见坑位与修复清单。



增量 Cube

  • 在大多数业务场景下,Hive 中的数据处于不断增长的状态

  • 为了支持在构建 Cube,无需重复处理历史数据,引入增量构建功能

Segment

Kylin 将 Cube 划分为多个 Segment(对应就是 HBase 中的一个表)


  • 一个 Cube 可能由 1 个或多个 Segment 组成,Segment 是指定时间范围的 Cube,可以理解为 Cube 的分区

  • Segment 是针对源数据中的某个片段计算出来的 Cube 数据,代表一段时间内源数据的预计计算结果

  • 每个 Segment 用起始时间和结束时间来标志

  • 一个 Segment 的起始时间等于它之前 Segment 的结束前时间,它的结束时间等于它后面那个 Segment 的起始时间

  • 同一个 Cube 下不同的 Segment 除了背后的源数据不同之外,其他如结构定义、构建过程、优化方法、存储方式等完全相同


Segment 示意图


例如:以下为针对某个 Cube 的 Segment


全量构建与增量构建

全量构建

在全量构建中:


  • Cube 中存在唯一一个 Segment

  • 每 Segment 没有分割时间的概念,即没有起始时间和结束时间

  • 对于全量构建来说,每当需要更新 Cube 数据时,它不会区分历史数据和新加入的数据,即在构建时导入并处理所有的数据

增量构建

在增量构建中:


  • 只会导入新 Segment 指定的时间区间内的原始数据,并只对这部分原始数据进行预计算

相互对比


全量构建与增量构建的 Cube 查询的方式对比:全量构建 Cube:


  • 查询引擎只需要向存储引擎访问单个 Segment 所对应的数据,无需进行 Segment 之间的聚合

  • 为了加强性能,单个 Segment 的数据也有可能被分片存储到引擎的多个分区上,查询引擎可能仍然需要对单个 Segment 不同分区的数据进一步聚合


增量构建 Cube:


  • 由于不同的时间的数据分布在不同的 Segment 中,查询引擎需要向存储引擎请求读取各个 Segment 的数据

  • 增量构建的 Cube 上的查询会比全量构建的做更多的运行时聚合,通常来说增量构建的 Cube 上查询会比全量构建的 Cube 上的查询要慢一些


对于小数据量的 Cube,或者经常需要全表更新的 Cube,使用全量构建需要更少的运维精力,以少量的重复计算降低生产环境中的维护复杂度。对于大数据量的 Cube,例一个包含较长历史数据的 Cube,如果每天更新,那么大量的资源是在用于重复计算,这个情况下可以考虑使用增量构建。

增量构建 Cube 过程

指定分割时间列

增量构建 Cube 的定义必须包含一个时间维度,用来分割不同的 Segment,这样的维度称为分割时间列(Partition Date Column)。

增量构建过程

  • 在进行增量构建时,将增量部分的起始时间和结束时间作为增量构建请求的一部分提交给 Kylin 的任务引擎

  • 任务引擎会根据起始时间和结束时间从 Hive 中抽取相应时间的数据,并对这部分数据做预处理计算

  • 将预计算的结果封装成一个新的 Segment,并将相应的信息保存到元数据和存储引擎中,一般来说,增量部分的起始时间等于 Cube 中最后一个 Segment 的结束时间

增量 Cube 构建

步骤:定义数据源 => 定义 Model => 定义 Cube => 构建 Cube

SQL 语句

-- 数据结构类似,只是改为了分区表drop table wzk_kylin.dw_sales1;create table wzk_kylin.dw_sales1(  id string,  channelId string,  productId string,  regionId string,  amount int,  price double)partitioned by (dt string)ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
-- 加载数据load data local inpath "dw_sales20240101_data.txt"into table wzk_kylin.dw_sales1partition(dt="2024-01-01");load data local inpath "dw_sales20240102_data.txt"into table wzk_kylin.dw_sales1partition(dt="2024-01-02");load data local inpath "dw_sales20240103_data.txt"into table wzk_kylin.dw_sales1partition(dt="2024-01-03");load data local inpath "dw_sales20240104_data.txt"into table wzk_kylin.dw_sales1partition(dt="2024-01-04");
复制代码

生成数据

同样,我们先编写一个脚本来生成对应的数据:


import random
# 设置参数dates = ["2024-01-01", "2024-01-02", "2024-01-03", "2024-01-04"]num_records_per_file = 100
# 定义可能的值channel_ids = ['C001', 'C002', 'C003', 'C004']product_ids = ['P001', 'P002', 'P003', 'P004']region_ids = ['R001', 'R002', 'R003', 'R004']
# 生成数据for dt in dates: output_file = f'dw_sales{dt.replace("-", "")}_data.txt' with open(output_file, 'w') as f: for i in range(num_records_per_file): record_id = f"{i+1:04d}" channel_id = random.choice(channel_ids) product_id = random.choice(product_ids) region_id = random.choice(region_ids) amount = random.randint(1, 100) price = round(random.uniform(10.0, 500.0), 2) line = f"{record_id},{channel_id},{product_id},{region_id},{amount},{price}\n" f.write(line) print(f"{num_records_per_file} records have been written to {output_file}")
print("All data files have been generated.")
复制代码


执行的结果如下图所示:


上传数据

通过你习惯的方式,将这几个 txt 上传到服务器上,准备执行:


执行脚本

hive -f kylin_partition.sql
复制代码


执行结果如下图:


加载数据源

Load Table From Tree



选择刚才创建的表,wzk_kylin.dw_sales1:


定义 Model

增量构建的 Cube 需要指定分割时间列,例如:将日期分区字段添加到维度列中:Data Model:New Join Condition,需要配置好几个:



配置成如下的结果:



维度配置如下图所示:



度量选择 AMOUNT 和 PRICE,最后的设置:


定义 Cube

填写名字等跳过,维度需要添加 DT、其他都要:



配置完的结果如下图:



度量配置如下:(Bulk Add Measures 快速配置)



剩余的信息都默认填写即可:


构建 Cube

接下来构建 Cube 的时候,进行 Build:



选部分的日期,就不选所有数据了:



继续等待构建完毕:


查看 Segment

刚才我们构建了


  • 2024-01-01 到 2024-01-02 的数据

  • 我们继续 build 2024-01-02 到 2024-01-03

  • 完成后继续 build 2024-01-03 到 2024-01-04 分段的进行 build 的任务,最后我们查看 Segment 如下:


2024-01-01 到 2024-01-02 完成之后,我们继续任务:



2024-01-02 到 2024-01-03 完成之后,我们继续任务:



漫长等待,任务都完成之后如下图所示:


查询测试

第一部分:按日期和地区汇总销售数据


-- 第一部分查询:按日期和地区汇总销售数据SELECT     t1.dt,    t2.regionname,    SUM(t1.price) AS total_money,    SUM(t1.amount) AS total_amount,    MAX(t1.price) AS max_price,    MIN(t1.amount) AS min_amountFROM     dw_sales1 t1JOIN     dim_region t2 ON     t1.regionid = t2.regionidGROUP BY     t1.dt,     t2.regionnameORDER BY     t1.dt;
复制代码


运行的结果如下图所示:



另一部分:按日期、地区和产品汇总销售数据


-- 第二部分查询:按日期、地区和产品汇总销售数据SELECT     t1.dt,    t2.regionid,    t2.regionname,    t3.productid,    t3.productname,    SUM(t1.price) AS total_money,    SUM(t1.amount) AS total_amountFROM     dw_sales1 t1INNER JOIN     dim_region t2 ON     t1.regionid = t2.regionidINNER JOIN     dim_product t3 ON     t1.productid = t3.productidGROUP BY     t1.dt,    t2.regionid,    t2.regionname,    t3.productid,    t3.productnameORDER BY     t1.dt,    t2.regionname,    t3.productname;
复制代码


查询结果如下图所示:


错误速查

其他系列

🚀 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 我热爱探索一切值得深究的事物。对技术、成长、效率、认知、人生有着持续的好奇心和行动力。 坚信「飞轮效应」,相信每一次微小的积累,终将带来深远的改变。

评论

发布
暂无评论
大数据-162 Apache Kylin 增量 Cube 与 Segment 实战:按天分区增量构建指南_大数据_武子康_InfoQ写作社区