大数据知识体系
首页
数据结构与算法
  • JVM
  • Java
  • Scala
  • Python
设计模式
  • MySQL
  • Redis
  • HDFS
  • HBase
  • ClickHouse
  • ElasticSearch
  • Iceberg
  • Hudi
  • Spark
  • Flink
  • Hive
  • Yarn
  • Zookeeper
  • Maven
  • Git
  • 数据仓库
  • 用户画像
  • 指标体系
数据治理
关于
首页
数据结构与算法
  • JVM
  • Java
  • Scala
  • Python
设计模式
  • MySQL
  • Redis
  • HDFS
  • HBase
  • ClickHouse
  • ElasticSearch
  • Iceberg
  • Hudi
  • Spark
  • Flink
  • Hive
  • Yarn
  • Zookeeper
  • Maven
  • Git
  • 数据仓库
  • 用户画像
  • 指标体系
数据治理
关于
  • 数据湖介绍
  • Iceberg

    • Iceberg 概述
    • Iceberg 数据类型
    • Iceberg 演化
    • Iceberg 分区
      • Iceberg 中分区的特点
      • 隐藏分区
    • Iceberg 文件组织形式
    • Iceberg Spark 入门
    • Iceberg Spark DDL
    • Iceberg Spark DQL
    • Iceberg Spark SQL 存储过程
  • Hudi

    • Hudi 概述
  • 数据湖
  • Iceberg
Will
2022-03-12
目录

Iceberg 分区

# Iceberg 中分区的特点

  • Iceberg 选中数据行中的某个字段作为分区,分区信息是记录至文件级别的。而 Hive 中选取的分区字段是以目录的形式出现的,最终的物理数据文件中(如 parquet 文件)是没有存储分区字段,也就是说 Hive 的分区是在目录级别的。
  • Iceberg 提供的隐藏分区可以根据查询条件自动过滤不需要的分区数据,使用者不需要关心表的分区字段,也不需要根据分区字段额外指定查询条件。
  • Iceberg 查询不再依赖于表的物理布局。随着物理和逻辑的分离,Iceberg 表可以随着数据量的变化而随着时间的推移演变分区方案,也就是说一个表中可以同时允许多个分区策略。
  • Iceberg 中针对每个数据文件都有记录了它的元数据信息,以及相关的统计信息。如:最大值、最小值、总行数、为 null 的行数等。

# 隐藏分区

隐藏分区,顾名思义就是将分区信息隐藏起来。开发人员只需要建表时指定分区策略,Iceberg 会根据分区策略跟踪该表字段与物理存储的数据文件之间的逻辑关系。使用者在插入和读取的时候不需要关心表的分区布局,不需要像 Hive 那样显示地指定分区字段,只需要关心业务逻辑即可。Iceberg 会在插入数据的时候根据分区策略跟踪新数据的分区信息,并将其记录在元数据中;查询的时候也会根据自动过滤掉不需要扫描的文件。

在 Hive 中使用分区,需要明确指定分区字段,而这些分区字段最终都会以目录的形式出现在文件系统中,其数据文件中不会出现。假设创建以下 Hive 表并插入一条数据:

create table user_log_1 (
    imei string,
    uuid string
)
partitioned by (udt string comment 'yyyy-MM-dd');

insert into user_log_1 partition (udt='2022-01-01') values ('xxxxxxxxxxxxx', 'yyyyyyyyyyyyy');
1
2
3
4
5
6
7

该表中的数据在文件系统中的组织形式是这样的:

user_log_1/
└── udt=2022-01-01
    ├── _SUCCESS
    └── part-00000-1f6ad6a0-3536-42f1-b354-d4ccb34a7939-c000
1
2
3
4

如果建表语句中指定 year、month、day 三个字段作为分区字段,并插入一条数据:

create table user_log_2 (
    imei string,
    uuid string
)
partitioned by (year int, month int, day int);

insert into user_log_2 partition (year=2022, month=1, day=1) values ('xxxxxxxxxxxxx', 'yyyyyyyyyyyyy');
1
2
3
4
5
6
7

该表中的数据在文件系统中的组织形式是这样的:

user_log_2/
└── year=2022
    └── month=1
        └── day=1
            ├── _SUCCESS
            └── part-00000-21bbea3f-350d-4b3f-a820-2d846184d9fc-c000
1
2
3
4
5
6

但是如果使用 Iceberg 来建表并插入一条数据:

create table hadoop_catalog.iceberg_db.user_log_iceberg (
    imei string,
    uuid string,
    udt timestamp
)
using iceberg
partitioned by (days(udt));

insert into hadoop_catalog.iceberg_db.user_log_iceberg values ('xxxxxxxxxxxxx', 'yyyyyyyyyyyyy', cast(1640966400 as timestamp));
1
2
3
4
5
6
7
8
9

查看表 user_log_iceberg 在文件系统中的存储结构:

user_log_iceberg/
├── data
│   └── udt_day=2021-12-31
│       └── 00000-0-67ab9286-794b-456d-a1d3-9c797a2b4b03-00001.parquet
└── metadata
    ├── f9d66153-6745-4103-ad24-334fc62f0d1e-m0.avro
    ├── snap-6744647507914918603-1-f9d66153-6745-4103-ad24-334fc62f0d1e.avro
    ├── v1.metadata.json
    ├── v2.metadata.json
    └── version-hint.text
1
2
3
4
5
6
7
8
9
10

其中data目录存储的是数据文件,metadata目录存储的是表的元数据信息,后续会详细介绍。

经过前面几个操作中,我们发现有以下几个不同:

  1. 在创建表 Iceberg 表的时候并没有像创建 Hive 表那样将分区字段放在partitioned by子句中,而是和其它字段一样放在表名后面的括号中,只是在partitioned by (days(udt))中指定了我们分区策略和udt字段之间的逻辑关系。
  2. Iceberg 表中插入数据的 SQL 相比 Hive 的插入 SQL 而言少了partition (year=2022, month=1, day=1)部分,也就是说没有额外去指定分区信息。
  3. 物理存储方面,Hive 的两个表数据文件part-00000-1f6ad6a0-3536-42f1-b354-d4ccb34a7939-c000和part-00000-21bbea3f-350d-4b3f-a820-2d846184d9fc-c000中没有udt、year、month、day几个分区字段的信息,分区字段体现在了目录中,但是在 Iceberg 表中,所有的字段数据都在00000-0-67ab9286-794b-456d-a1d3-9c797a2b4b03-00001.parquet文件中,且自动转换了分区策略和字段时间的关系。
  4. Hive 表中如果要使用分区键进行查询,开发人员必须先查看该表的建表语句以了解该表的物理存储方式,但使用 Iceberg 表时不需要关心物理存储。
  5. 假设在使用表user_log_1的时候将查询条件中的条件指定为udt = '20220101'(日期格式为 yyyyMMdd),查询不会报错,但是可能会返回一个错误的结果。

在user_log_iceberg表中的分区策略中使用到了days函数,将timestamp中的day作为分区属性,实际上除了将timestamp转换为day,还支持其它转换:

转换方式 描述 原类型 转换后的类型
identity 原值,不进行修改 所有类型型 转换后的类型和原类型对应
bucket[N] 采用哈市算法分桶 int, long, decimal, date, time, timestamp, timestamptz, string, uuid, fixed, binary int
truncate[W] 截取固定长度进行分区 int, long, decimal, string 转换后的类型和原类型对应
year 提取 date 或 timestamp 中的 year 信息 date, timestamp, timestampz int
month 提取 date 或 timestamp 中的 month 信息 date, timestamp, timestampz int
day 提取 date 或 timestamp 中的 day 信息 date, timestamp, timestampz int
hour 提取 timestamp 中的 hour 信息 timestamp, timestampz int
void 无论元数据等于什么,输出为 null 所有类型 原型类或 int

提示

  1. 所有的转换都允许输入为 null,输出为 null;
  2. 以上转换方式列对应的值只代表具体的转换方式,并不是在 SQL 中使用的转换函数,如转换方式day在 Spark SQL 中对应的转换函数为days。
上次更新: 2023/11/01, 03:11:44

← Iceberg 演化 Iceberg 文件组织形式→

Theme by Vdoing | Copyright © 2022-2023 Will 蜀ICP备2022002285号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式