在 Iceberg V3 表中使用二进制删除向量

Lakehouse 运行时目录支持 Apache Iceberg V3 表。Apache Iceberg V3 规范的一项核心功能是二进制删除向量。此优化功能将行级删除操作存储在 .puffin 文件中。BigQuery 和开源引擎(例如 Apache Spark、Apache Flink 和 Trino)无需在查询时执行开销巨大的联接操作,而是使用这些向量快速识别并跳过已删除的行。

使用二进制删除向量可以通过以下方式提升性能:

  • 大容量写入:提高大容量写入表的写入性能。
  • 高效读取:通过允许 BigQuery 和开源引擎识别并跳过已删除的行,提高查询速度。

这对于在变更数据捕获 (CDC) 流水线中处理大量更新和删除操作,或者通过删除特定行来满足 GDPR(被遗忘权)等监管要求特别有用,而无需重写整个数据文件,从而减少开销。

准备工作

  1. 验证是否已为您的 Google Cloud 项目启用结算功能

  2. 启用 BigLake API。

    启用 API 所需的角色

    如需启用 API,您需要拥有 Service Usage Admin IAM 角色 (roles/serviceusage.serviceUsageAdmin),该角色包含 serviceusage.services.enable 权限。了解如何授予角色

    启用 API

所需的角色

如需获得创建和管理 Iceberg V3 表所需的权限,请让您的管理员为您授予项目和存储桶的以下 IAM 角色:

  • 全部:
    • BigLake Admin (roles/biglake.admin) - 您的项目
    • Storage Admin (roles/storage.admin) - 目标 Cloud Storage 存储桶

如需详细了解如何授予角色,请参阅管理对项目、文件夹和组织的访问权限

您也可以通过自定义角色或其他预定义角色来获取所需的权限。

设置 Iceberg REST 目录

在创建 Iceberg V3 表之前,您必须设置 Iceberg REST 目录,包括创建命名空间和目录。

设置 Iceberg REST 目录可能需要一些时间才能完成。请确保您已成功创建命名空间和目录,然后再继续。

限制

Lakehouse 运行时目录中的 Iceberg V3 表具有以下限制:

  • 新的 V3 数据类型:不支持新的 Iceberg V3 数据类型(例如 Variant、Geography、纳秒时间戳、默认值和未知数据类型)。
  • 行级沿袭跟踪:不支持行级沿袭跟踪。
  • BigQuery 写入:V3 表不支持 BigQuery 写入。您只能从 BigQuery 读取 V3 表。如需创建 V3 表并向其中写入数据,您必须使用开源引擎(例如 Apache Spark、Apache Flink 或 Trino)。

引擎要求

请确保您使用的引擎版本支持 Iceberg V3 和二进制删除向量。建议使用 Apache Spark 3.5 或更高版本。本指南中的示例使用 iceberg-spark-runtime-3.5_2.12:1.10.1

配置表和引擎会话时,请确保:

  • 表格格式版本:必须设置为 format-version='3'
  • 删除模式:必须设置为 merge-on-read。此模式可确保将删除操作写入单独的文件(删除向量),而不是重写原始数据文件(写入时复制)。

Spark 会话配置示例

以下配置可启用必要的 Iceberg 扩展程序并设置 REST 目录连接:

spark-sql \
    --packages org.apache.iceberg:iceberg-spark-runtime-3.5_2.12:1.10.1,org.apache.iceberg:iceberg-gcp:1.10.1 \
    --jars https://storage-download.googleapis.com/maven-central/maven2/org/apache/iceberg/iceberg-gcp-bundle/1.10.1/iceberg-gcp-bundle-1.10.1.jar \
    --conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions \
    --conf spark.sql.catalog.CATALOG_NAME=org.apache.iceberg.spark.SparkCatalog \
    --conf spark.sql.catalog.CATALOG_NAME.type=rest \
    --conf spark.sql.catalog.CATALOG_NAME.uri=https://biglake.googleapis.com/iceberg/v1/restcatalog \
    --conf spark.sql.catalog.CATALOG_NAME.warehouse=WAREHOUSE_PATH \
    --conf spark.sql.catalog.CATALOG_NAME.header.x-goog-user-project=PROJECT_ID \
    --conf spark.sql.catalog.CATALOG_NAME.rest.auth.type=org.apache.iceberg.gcp.auth.GoogleAuthManager \
    --conf spark.sql.catalog.CATALOG_NAME.io-impl=org.apache.iceberg.gcp.gcs.GCSFileIO \
    --conf spark.sql.defaultCatalog=CATALOG_NAME

替换以下内容:

  • CATALOG_NAME:Apache Iceberg REST 目录端点的名称。
  • WAREHOUSE_PATH:存储数据仓库的 Cloud Storage 文件夹的 URI,以 gs:// 开头。
  • PROJECT_ID:您的 Google Cloud 项目 ID。

使用二元删除向量

如需在 Apache Iceberg V3 表中使用二进制删除向量,您必须创建格式版本为 3 的表,使用数据填充该表,执行标准数据库修改,然后查询该表。您可以使用 Spark SQL 运行所有创建、插入、删除和更新语句。

创建具有二进制删除向量的 Iceberg 表

创建表,并在表属性中指定 format-version='3'merge-on-read 删除、更新和合并模式。在 Spark SQL 中运行以下语句:

Spark

CREATE NAMESPACE IF NOT EXISTS my_namespace;
USE my_namespace;

CREATE TABLE my_namespace.mytable_v3 (
   id BIGINT,
   city STRING,
   state STRING
) TBLPROPERTIES (
   'format-version'='3',
   'write.delete.mode'='merge-on-read',
   'write.update.mode'='merge-on-read',
   'write.merge.mode'='merge-on-read'
);

将 Iceberg V2 表升级到 V3

您可以使用 ALTER TABLE 语句将现有的 Iceberg V2 表升级到 V3。不支持将表从 V3 降级到 V2。在 Spark SQL 中运行以下语句:

Spark

ALTER TABLE my_namespace.mytable_v2 SET TBLPROPERTIES ('format-version' = '3');

将数据插入到表中

为确保为删除操作生成二进制删除向量文件,引擎不得回退到写入时复制。通常,在执行删除操作之前,表中需要有大量数据。例如,Apache Spark 可能会通过回退到写入时复制来优化小型删除操作。在 Spark SQL 中运行以下语句,以填充表:

Spark

-- Create a temporary view with a large number of rows (100,000 rows)
CREATE OR REPLACE TEMPORARY VIEW large_source AS
SELECT
  id,
  CAST(id AS STRING) as city,
  'WA' as state
FROM (
  SELECT row_number() OVER (ORDER BY (SELECT NULL)) as id
  FROM (SELECT 0 FROM range(1000)) a
  CROSS JOIN (SELECT 0 FROM range(100)) b
);

-- Overwrite the existing table with the generated data
INSERT OVERWRITE my_namespace.mytable_v3 SELECT * FROM large_source;

删除数据

在 Spark SQL 中执行 DELETE 语句。由于该表已配置为 merge-on-read 且具有足够的数据,因此 Spark 会使用二进制删除向量生成删除文件。

Spark

DELETE FROM my_namespace.mytable_v3 WHERE id = 5000;

更新数据

在 Spark SQL 中执行 UPDATE 语句。由于该表已配置为 merge-on-read 且具有足够的数据,因此 Spark 会使用二进制删除向量生成删除文件。

Spark

UPDATE my_namespace.mytable_v3 SET state = 'NY' WHERE id = 1;

查询表

对该表的查询会自动使用二进制删除向量文件来排除已删除的行。您可以使用 Apache Spark 或 BigQuery 查询该表。

Spark

-- Should be less than the initial 100,000 rows
SELECT count(*) FROM my_namespace.mytable_v3;

-- Should return no results
SELECT * FROM my_namespace.mytable_v3 WHERE id = 5000;

-- Should return 'NY'
SELECT * FROM my_namespace.mytable_v3 WHERE id = 1;

BigQuery

从 BigQuery 进行查询时,请使用完全限定的表标识符 PROJECT_ID.CATALOG_NAME.my_namespace.mytable_v3

bq query --nouse_legacy_sql \
    'SELECT * FROM `PROJECT_ID.CATALOG_NAME.my_namespace.mytable_v3` LIMIT 10'

验证二进制删除向量的创建

您可以通过检查存储目录和快照元数据来验证是否已成功创建二元删除向量。

检查是否有 .puffin 文件

在 Cloud Storage 数据仓库中找到相应表的数据目录(例如 gs://WAREHOUSE_BUCKET/my_namespace/mytable_v3/data)。您应该会看到存储二进制删除向量的 .puffin 文件。

检查快照元数据

Iceberg 表的 JSON 文件中的快照元数据包含有关删除操作的信息。在快照摘要中查找 added-delete-filesadded-dvsoperation 等属性。这可确认是否已添加删除文件。

"summary": {
  "operation": "delete",
  "added-delete-files": "1",
  "added-dvs": "1",
  "added-files-size": "42",
  "added-position-deletes": "1",
  ...
}

后续步骤