要在 Spark 中使用 Iceberg,请首先配置 Spark 目录。 Iceberg 使用 Apache Spark 的 DataSourceV2 API 来实现数据源和目录。
Spark 3 可以使用 USINGiceberg 子句在任何 Iceberg 目录中创建表:
CREATE TABLE prod.db.sample (
id bigint COMMENT 'unique id',
data string)
USING iceberg
Iceberg会将Spark中的列类型转换为对应的Iceberg类型。详细信息请查看创建表的类型兼容性部分。
创建命令还可以使用 USING 子句设置默认格式。仅 SparkCatalog 支持此功能,因为 Spark 对内置目录的 USING 子句的处理方式不同。
要创建分区表,请使用 PARTITIONED BY:
CREATE TABLE prod.db.sample (
id bigint,
data string,
category string)
USING iceberg
PARTITIONED BY (category)
PARTITIONED BY 子句支持转换表达式来创建隐藏分区。
CREATE TABLE prod.db.sample (
id bigint,
data string,
category string,
ts timestamp)
USING iceberg
PARTITIONED BY (bucket(16, id), days(ts), category)
支持的转换有:
注意:为了兼容性,还支持年(ts)、月(ts)、日(ts)和小时(ts)的旧语法。
使用 SparkCatalog 时,Iceberg 支持 CTAS 作为原子操作。支持 CTAS,但在使用 SparkSessionCatalog 时不是原子的。
CREATE TABLE prod.db.sample
USING iceberg
AS SELECT ...
新创建的表不会继承 SELECT 中源表的分区规范和表属性,您可以使用 CTAS 中的 PARTITIONED BY 和 TBLPROPERTIES 来声明新表的分区规范和表属性。
CREATE TABLE prod.db.sample
USING iceberg
PARTITIONED BY (part)
TBLPROPERTIES ('key'='value')
AS SELECT ...
使用 SparkCatalog 时,Iceberg 支持 RTAS 作为原子操作。支持 RTAS,但在使用 SparkSessionCatalog 时不是原子的。
原子表替换使用 SELECT 查询的结果创建新快照,但保留表历史记录。
REPLACE TABLE prod.db.sample
USING iceberg
AS SELECT ...
REPLACE TABLE prod.db.sample
USING iceberg
PARTITIONED BY (part)
TBLPROPERTIES ('key'='value')
AS SELECT ...
CREATE OR REPLACE TABLE prod.db.sample
USING iceberg
AS SELECT ...
删除表行为在 0.14 中发生了变化。
在 0.14 之前,运行 DROP TABLE 将从目录中删除表并删除表内容。
从 0.14 开始,DROP TABLE 只会从目录中删除表。为了删除表内容,应使用 DROP TABLE PURGE。
DROP TABLE
要从目录中删除表,请运行:
DROP TABLE prod.db.sample
DROP TABLE PURGE
要从目录中删除表并删除表的内容,请运行:
DROP TABLE prod.db.sample PURGE
Iceberg 在 Spark 3 中拥有完整的 ALTER TABLE 支持,包括:
此外,SQL 扩展可用于添加对分区演化和设置表的写入顺序的支持
ALTER TABLE prod.db.sample RENAME TO prod.db.new_name
ALTER TABLE prod.db.sample SET TBLPROPERTIES (
'read.split.target-size'='268435456'
)
Iceberg 使用表属性来控制表行为。
UNSET 用于删除属性:
ALTER TABLE prod.db.sample UNSET TBLPROPERTIES ('read.split.target-size')
SET TBLPROPERTIES 还可以用来设置表注释(描述):
ALTER TABLE prod.db.sample SET TBLPROPERTIES (
'comment' = 'A table comment.'
)
要将列添加到 Iceberg,请使用 ADD COLUMNS 子句和 ALTER TABLE:
ALTER TABLE prod.db.sample
ADD COLUMNS (
new_column string comment 'new_column docs'
)
可以同时添加多列,以逗号分隔。
应使用完整的列名称来标识嵌套列:
-- create a struct column
ALTER TABLE prod.db.sample
ADD COLUMN point struct<x: double, y: double>;
-- add a field to the struct
ALTER TABLE prod.db.sample
ADD COLUMN point.z double
-- create a nested array column of struct
ALTER TABLE prod.db.sample
ADD COLUMN points array<struct<x: double, y: double>>;
-- add a field to the struct within an array. Using keyword 'element' to access the array's element column.
ALTER TABLE prod.db.sample
ADD COLUMN points.element.z double
-- create a map column of struct key and struct value
ALTER TABLE prod.db.sample
ADD COLUMN points map<struct<x: int>, struct<a: int>>;
-- add a field to the value struct in a map. Using keyword 'value' to access the map's value column.
ALTER TABLE prod.db.sample
ADD COLUMN points.value.b int
注意:不允许通过添加列来更改映射“键”列。只能更新地图值。
通过添加 FIRST 或 AFTER 子句在任意位置添加列:
ALTER TABLE prod.db.sample
ADD COLUMN new_column bigint AFTER other_column
ALTER TABLE prod.db.sample
ADD COLUMN nested.new_column bigint FIRST
Iceberg 允许重命名任何字段。要重命名字段,请使用 RENAME COLUMN:
ALTER TABLE prod.db.sample RENAME COLUMN data TO payload
ALTER TABLE prod.db.sample RENAME COLUMN location.lat TO latitude
请注意,嵌套重命名命令仅重命名叶字段。上述命令将 location.lat 重命名为 location.latitude
更改列用于扩大类型、使字段可选、设置注释以及重新排序字段。
如果更新是安全的,Iceberg 允许更新列类型。安全更新是:
ALTER TABLE prod.db.sample ALTER COLUMN measurement TYPE double
要从结构中添加或删除列,请使用带有嵌套列名称的 ADD COLUMN 或 DROP COLUMN。
列注释也可以使用 ALTER COLUMN 进行更新:
ALTER TABLE prod.db.sample ALTER COLUMN measurement TYPE double COMMENT 'unit is bytes per second'
ALTER TABLE prod.db.sample ALTER COLUMN measurement COMMENT 'unit is kilobytes per second'
Iceberg 允许使用 FIRST 和 AFTER 子句对顶级列或结构中的列进行重新排序:
ALTER TABLE prod.db.sample ALTER COLUMN col FIRST
ALTER TABLE prod.db.sample ALTER COLUMN nested.col AFTER other_col
可以使用 DROP NOT NULL 更改不可为空列的可为空性:
ALTER TABLE prod.db.sample ALTER COLUMN id DROP NOT NULL
无法使用 SET NOT NULL 将可空列更改为不可空列,因为 Iceberg 不知道是否存在具有空值的现有数据。
ALTER COLUMN 不用于更新结构类型。使用 ADD COLUMN 和 DROP COLUMN 添加或删除结构字段。
要删除列,请使用 ALTER TABLE … DROP COLUMN:
ALTER TABLE prod.db.sample DROP COLUMN id
ALTER TABLE prod.db.sample DROP COLUMN point.z
ALTER TABLE SQL extensions
使用 Iceberg SQL 扩展时,这些命令在 Spark 3 中可用。
Iceberg 支持使用 ADD PARTITION FIELD 将新的分区字段添加到规范中:
ALTER TABLE prod.db.sample ADD PARTITION FIELD catalog
还支持分区转换:
ALTER TABLE prod.db.sample ADD PARTITION FIELD bucket(16, id)
ALTER TABLE prod.db.sample ADD PARTITION FIELD truncate(4, data)
ALTER TABLE prod.db.sample ADD PARTITION FIELD year(ts)
-- use optional AS keyword to specify a custom name for the partition field
ALTER TABLE prod.db.sample ADD PARTITION FIELD bucket(16, id) AS shard
添加分区字段是元数据操作,不会更改任何现有表数据。新数据将使用新分区写入,但现有数据将保留在旧分区布局中。旧数据文件的元数据表中的新分区字段将为空值。
当表的分区发生变化时,动态分区覆盖行为也会发生变化,因为动态覆盖会隐式替换分区。要显式覆盖,请使用新的 DataFrameWriterV2 API。
要通过转换从每日分区迁移到每小时分区,无需删除每日分区字段。保留该字段可确保现有元数据表查询继续工作。
当分区发生变化时,动态分区覆盖行为也会发生变化。例如,如果您按天分区并改为按小时分区,则覆盖将覆盖每小时分区,但不再覆盖天分区。
可以使用 DROP PARTITION FIELD 删除分区字段:
ALTER TABLE prod.db.sample DROP PARTITION FIELD catalog
ALTER TABLE prod.db.sample DROP PARTITION FIELD bucket(16, id)
ALTER TABLE prod.db.sample DROP PARTITION FIELD truncate(4, data)
ALTER TABLE prod.db.sample DROP PARTITION FIELD year(ts)
ALTER TABLE prod.db.sample DROP PARTITION FIELD shard
请注意,尽管删除了分区,但该列仍将存在于表模式中。
删除分区字段是元数据操作,不会更改任何现有表数据。新数据将使用新分区写入,但现有数据将保留在旧分区布局中。
当分区更改时,动态分区覆盖行为将会改变。例如,如果您按天分区并转为按小时分区,则覆盖将覆盖每小时分区,但不再覆盖天分区。
删除分区字段时要小心,因为它会更改元数据表(如文件)的架构,并可能导致元数据查询失败或产生不同的结果。
通过使用 REPLACE PARTITION FIELD,可以在单个元数据更新中将分区字段替换为新的分区字段:
ALTER TABLE prod.db.sample REPLACE PARTITION FIELD ts_day WITH day(ts)
-- use optional AS keyword to specify a custom name for the new partition field
ALTER TABLE prod.db.sample REPLACE PARTITION FIELD ts_day WITH day(ts) AS day_of_ts
Iceberg 表可以配置排序顺序,用于自动对某些引擎中写入表的数据进行排序。例如,Spark 中的 MERGE INTO 将使用表排序。
要设置表的写入顺序,请使用 WRITE ORDERED BY:
ALTER TABLE prod.db.sample WRITE ORDERED BY category, id
-- use optional ASC/DEC keyword to specify sort order of each field (default ASC)
ALTER TABLE prod.db.sample WRITE ORDERED BY category ASC, id DESC
-- use optional NULLS FIRST/NULLS LAST keyword to specify null order of each field (default FIRST)
ALTER TABLE prod.db.sample WRITE ORDERED BY category ASC NULLS LAST, id DESC NULLS FIRST
表写入顺序不保证查询的数据顺序。它仅影响数据写入表的方式。
WRITE ORDERED BY 设置全局排序,其中行跨任务排序,就像在 INSERT 命令中使用 ORDER BY 一样:
INSERT INTO prod.db.sample
SELECT id, data, category, ts FROM another_table
ORDER BY ts, category
要在每个任务内而不是跨任务排序,请使用 LOCALLY ORDERED BY:
ALTER TABLE prod.db.sample WRITE LOCALLY ORDERED BY category, id
WRITE DISTRIBUTED BY PARTITION 会要求每个分区由一个 writer 处理,默认实现是哈希分布。
ALTER TABLE prod.db.sample WRITE DISTRIBUTED BY PARTITION
DISTRIBUTED BY PARTITION 和 LOCALLY ORDERED BY 可以一起使用,以按分区分布并在每个任务中本地排序行。
ALTER TABLE prod.db.sample WRITE DISTRIBUTED BY PARTITION LOCALLY ORDERED BY category, id
Iceberg 支持使用 SET IDENTIFIER FIELDS 将标识符字段设置为规范:
ALTER TABLE prod.db.sample SET IDENTIFIER FIELDS id
-- single column
ALTER TABLE prod.db.sample SET IDENTIFIER FIELDS id, data
-- multiple columns
标识符字段必须为 NOT NULL,后面的 ALTER 语句将覆盖之前的设置。
可以使用 DROP IDENTIFIER FIELDS 删除标识符字段:
ALTER TABLE prod.db.sample DROP IDENTIFIER FIELDS id
-- single column
ALTER TABLE prod.db.sample DROP IDENTIFIER FIELDS id, data
-- multiple columns
请注意,尽管标识符已被删除,但该列仍将存在于表架构中。
分支和标记 DDL
可以通过 CREATE BRANCH 语句使用以下选项创建分支:
-- CREATE audit-branch at current snapshot with default retention.
ALTER TABLE prod.db.sample CREATE BRANCH `audit-branch`
-- CREATE audit-branch at current snapshot with default retention if it doesn't exist.
ALTER TABLE prod.db.sample CREATE BRANCH IF NOT EXISTS `audit-branch`
-- CREATE audit-branch at current snapshot with default retention or REPLACE it if it already exists.
ALTER TABLE prod.db.sample CREATE OR REPLACE BRANCH `audit-branch`
-- CREATE audit-branch at snapshot 1234 with default retention.
ALTER TABLE prod.db.sample CREATE BRANCH `audit-branch`
AS OF VERSION 1234
-- CREATE audit-branch at snapshot 1234, retain audit-branch for 31 days, and retain the latest 31 days. The latest 3 snapshot snapshots, and 2 days worth of snapshots.
ALTER TABLE prod.db.sample CREATE BRANCH `audit-branch`
AS OF VERSION 1234 RETAIN 30 DAYS
WITH SNAPSHOT RETENTION 3 SNAPSHOTS 2 DAYS
可以通过 CREATE TAG 语句使用以下选项创建标签:
-- CREATE historical-tag at current snapshot with default retention.
ALTER TABLE prod.db.sample CREATE TAG `historical-tag`
-- CREATE historical-tag at current snapshot with default retention if it doesn't exist.
ALTER TABLE prod.db.sample CREATE TAG IF NOT EXISTS `historical-tag`
-- CREATE historical-tag at current snapshot with default retention or REPLACE it if it already exists.
ALTER TABLE prod.db.sample CREATE OR REPLACE TAG `historical-tag`
-- CREATE historical-tag at snapshot 1234 with default retention.
ALTER TABLE prod.db.sample CREATE TAG `historical-tag` AS OF VERSION 1234
-- CREATE historical-tag at snapshot 1234 and retain it for 1 year.
ALTER TABLE prod.db.sample CREATE TAG `historical-tag`
AS OF VERSION 1234 RETAIN 365 DAYS
分支引用的快照可以通过 REPLACE BRANCH sql 进行更新。保留也可以在此声明中更新。
-- REPLACE audit-branch to reference snapshot 4567 and update the retention to 60 days.
ALTER TABLE prod.db.sample REPLACE BRANCH `audit-branch`
AS OF VERSION 4567 RETAIN 60 DAYS
标签引用的快照可以通过 REPLACE TAG sql 进行更新。保留也可以在此声明中更新。
-- REPLACE historical-tag to reference snapshot 4567 and update the retention to 60 days.
ALTER TABLE prod.db.sample REPLACE TAG `historical-tag`
AS OF VERSION 4567 RETAIN 60 DAYS
可以通过 DROP BRANCH sql 删除分支
ALTER TABLE prod.db.sample DROP BRANCH `audit-branch`
可以通过 DROP TAG sql 删除标签
ALTER TABLE prod.db.sample DROP TAG `historical-tag`