为 Apache Iceberg 创建 BigLake 外部表

借助 BigLake 外部表,您可以以只读格式访问具有更精细访问权限控制的 Apache Iceberg 表。与适用于 Apache Iceberg 的 BigQuery 表不同,该功能可让您以可写入的格式在 BigQuery 中创建 Apache Iceberg 表。

Iceberg 是一种支持 PB 级数据表的开源表格式。Iceberg 的开放式规范让您能够对存储在对象存储区中的数据的单个副本运行多个查询引擎。

作为 BigQuery 管理员,您可以强制执行行级和列级访问权限控制,包括对表执行数据遮盖。如需了解如何在表级层设置访问权限控制,请参阅设置访问权限控制政策。将 BigQuery Storage API 用作 Dataproc 和无服务器 Spark 中表的数据源时,也会强制执行表访问权限政策。此外,BigLake 表还可与其他 BigQuery 服务进行集成。如需查看可用集成的完整列表,请参阅 BigLake 表简介

您可以采用以下方法创建 Iceberg BigLake 表:

  • 使用 BigLake Metastore(建议用于 Google Cloud)。BigLake Metastore 是一个自定义 Iceberg 目录。建议您对 Google Cloud 使用 BigLake Metastore,因为它可在 Spark 和 BigQuery 工作负载之间同步您的表。为此,您可以使用适用于 Apache Spark 的 BigQuery 存储过程来初始化 BigLake Metastore 并创建 Iceberg BigLake 表。但是,若要更新架构,仍需要您在 BigQuery 中运行一个更新查询。

  • 使用 AWS Glue Data Catalog(建议用于 AWS)。建议您对 AWS 使用 AWS Glue,因为它是一个集中式元数据仓库,您可以在其中定义存储在各种 AWS 服务中的数据的结构和位置,并提供各种功能(例如自动架构发现以及与 AWS 分析工具的集成)。

  • 使用 Iceberg JSON 元数据文件(建议用于 Azure)。如果使用 Iceberg JSON 元数据文件,则每当有表更新时,您都必须手动更新最新的元数据文件。您可以使用适用于 Apache Spark 的 BigQuery 存储过程来创建引用 Iceberg 元数据文件的 Iceberg BigLake 表。为避免这种情况,您可以对 Google Cloud 使用 BigLake Metastore,或是对 AWS 使用 AWS Glue Data Catalog

    如需查看相关限制的完整列表,请参阅限制

准备工作

  • Enable the BigQuery Connection, BigQuery Reservation, and BigLake APIs.

    Enable the APIs

  • 如果您在 BigQuery 中使用 Spark 的存储过程来创建 Iceberg BigLake 表,则必须执行以下步骤:

    1. 创建 Spark 连接
    2. 为该连接设置访问权限控制
  • 如需将 Iceberg BigLake 表元数据和数据文件存储在 Cloud Storage 中,您还需创建 Cloud Storage 存储桶。您需要连接到该 Cloud Storage 存储桶才能访问元数据文件。请按以下步骤操作:

    1. 创建 Cloud 资源连接
    2. 设置该连接的访问权限
  • 如果您使用的是 BigLake Metastore,请安装适用于 Apache Spark 的相应 Iceberg 自定义目录。选择与您使用的 Iceberg 版本最匹配的 Custom Catalog 版本。

    1. Iceberg 1.5.0:gs://spark-lib/biglake/biglake-catalog-iceberg1.5.0-0.1.1-with-dependencies.jar
    2. Iceberg 1.2.0:gs://spark-lib/biglake/biglake-catalog-iceberg1.2.0-0.1.1-with-dependencies.jar
    3. Iceberg 0.14.0:gs://spark-lib/biglake/biglake-catalog-iceberg0.14.0-0.1.1-with-dependencies.jar

所需的角色

如需确保 BigLake API 的调用方拥有创建 BigLake 表所需的权限,请让管理员向 BigLake API 的调用方授予项目的以下 IAM 角色:

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

这些预定义角色包含创建 BigLake 表所需的权限。如需查看所需的确切权限,请展开所需权限部分:

所需权限

如需创建 BigLake 表,需要以下权限:

  • bigquery.tables.create
  • bigquery.connections.delegate
  • bigquery.jobs.create

您的管理员也可以使用自定义角色或其他预定义角色向 BigLake API 的调用方授予这些权限。

此外,如需允许 BigQuery 用户查询表,与连接关联的服务账号必须具有 BigLake Viewer (roles/biglake.viewer) 角色,以及包含该数据的 Cloud Storage 存储桶的访问权限。

如需使用 BigLake Metastore 创建 Iceberg BigLake 表,则 BigLake API 的调用方会更改。您必须向 Dataproc 或 Spark 服务账号授予访问包含该数据的 Cloud Storage 存储桶的权限:

使用 BigLake Metastore 创建表

我们建议您使用 BigLake Metastore 创建 Iceberg BigLake 表。您可以使用 Apache Spark 创建这些表。一种执行此操作的便捷方法是使用 Spark 的 BigQuery 存储过程,具体步骤如下:

  1. 转到 BigQuery 页面。

    转到 BigQuery

  2. 探索器窗格中,点击项目中您用于创建连接资源的连接。

  3. 如需为 Spark 创建存储过程,请点击 创建存储过程

  4. 在查询编辑器中,使用显示的 CREATE PROCEDURE 语句修改示例代码,以初始化 BigLake Metastore 并为 Iceberg 创建 BigLake 外部表:

     # Creates a stored procedure that initializes BLMS and database.
     # Creates a table in the database and populates a few rows of data.
     CREATE OR REPLACE PROCEDURE iceberg_demo.iceberg_setup_3_3 ()
     WITH CONNECTION `PROCEDURE_CONNECTION_PROJECT_ID.PROCEDURE_CONNECTION_REGION.PROCEDURE_CONNECTION_ID`
     OPTIONS(engine="SPARK",
     jar_uris=["gs://spark-lib/biglake/biglake-catalog-iceberg1.2.0-0.1.0-with-dependencies.jar"],
     properties=[
     ("spark.jars.packages","org.apache.iceberg:iceberg-spark-runtime-3.3_2.12:1.2.0"),
     ("spark.sql.catalog.CATALOG", "org.apache.iceberg.spark.SparkCatalog"),
     ("spark.sql.catalog.CATALOG.catalog-impl", "org.apache.iceberg.gcp.biglake.BigLakeCatalog"),
     ("spark.sql.catalog.CATALOG.hms_uri", "HMS_URI"),
     ("spark.sql.catalog.CATALOG.gcp_project", "PROJECT_ID"),
     ("spark.sql.catalog.CATALOG.gcp_location", "LOCATION"),
     ("spark.sql.catalog.CATALOG.blms_catalog", "CATALOG"),
     ("spark.sql.catalog.CATALOG.warehouse", "DATA_WAREHOUSE_URI")
     ]
     )
     LANGUAGE PYTHON AS R'''
     from pyspark.sql import SparkSession
    
     spark = SparkSession \
       .builder \
       .appName("BigLake Iceberg Example") \
       .enableHiveSupport() \
       .getOrCreate()
    
     spark.sql("CREATE NAMESPACE IF NOT EXISTS CATALOG;")
     spark.sql("CREATE DATABASE IF NOT EXISTS CATALOG.CATALOG_DB;")
     spark.sql("DROP TABLE IF EXISTS CATALOG.CATALOG_DB.CATALOG_TABLE;")
    
     # Create a BigLake Metastore table and a BigQuery Iceberg table.
     spark.sql("CREATE TABLE IF NOT EXISTS CATALOG.CATALOG_DB.CATALOG_TABLE (id bigint, demo_name string)
               USING iceberg
               TBLPROPERTIES(bq_table='BQ_DATASET.BQ_TABLE', bq_connection='TABLE_CONNECTION_PROJECT_ID.TABLE_CONNECTION_REGION.TABLE_CONNECTION_ID');
               ")
    
     # Copy a Hive Metastore table to BigLake Metastore. Can be used together with
     #   TBLPROPERTIES `bq_table` to create a BigQuery Iceberg table.
     spark.sql("CREATE TABLE CATALOG.CATALOG_DB.CATALOG_TABLE (id bigint, demo_name string)
                USING iceberg
                TBLPROPERTIES(hms_table='HMS_DB.HMS_TABLE');")
     ''';
    

    替换以下内容:

    • PROCEDURE_CONNECTION_PROJECT_ID:包含用于运行 Spark 过程的连接的项目,例如 myproject

    • PROCEDURE_CONNECTION_REGION:包含用于运行 Spark 过程的连接的区域,例如 us

    • PROCEDURE_CONNECTION_ID:连接 ID,例如 myconnection

      当您在 Google Cloud 控制台中查看连接详情时,连接 ID 是连接 ID 中显示的完全限定连接 ID 的最后一部分中的值,例如 projects/myproject/locations/connection_location/connections/myconnection

    • CATALOG:要为 BigLake Metastore 创建的 Iceberg 目录的名称。

      默认值为 iceberg

    • HMS_URI:如果您要将现有的 Hive Metastore 表复制到 BigLake Metastore,请指定 Hive Metastore URI。

      例如 thrift://localhost:9083

    • PROJECT_ID:要在其中创建 BigLake Metastore 实例的项目的 ID。

      Iceberg BigLake 表也会在同一项目中创建。

    • LOCATION:要在其中创建 BigLake Metastore 实例的位置。

      BigQuery 只能访问存储在相同位置的 BigLake Metastore 实例。

    • DATA_WAREHOUSE_URI:您为存储 Iceberg 元数据和数据文件而创建的 Cloud Storage 存储桶的 URI。

      例如 gs://mybucket/iceberg-warehouse

    • CATALOG_DB:您要在 BigLake Metastore 中创建的数据库的名称。

      此数据库等效于将包含 Iceberg BigLake 表的 BigQuery 数据集。

    • CATALOG_TABLE:您要在 BigLake Metastore 中创建的表的名称。

      此表等效于要创建的 Iceberg BigLake 表。

    • BQ_DATASET:包含 Iceberg BigLake 表的 BigQuery 数据集。

    • BQ_TABLE:您要创建的 Iceberg BigLake 表。

    • TABLE_CONNECTION_PROJECT_ID:包含用于创建 BigLake 表的连接的项目,例如 myproject

    • TABLE_CONNECTION_REGION:包含用于创建 BigLake 表的连接的区域,例如 us

    • TABLE_CONNECTION_ID:连接 ID,例如 myconnection

      当您在 Google Cloud 控制台中查看连接详情时,连接 ID 是连接 ID 中显示的完全限定连接 ID 的最后一部分中的值,例如 projects/myproject/locations/connection_location/connections/myconnection

      与该连接关联的服务账号必须具有 roles/biglake.viewer 才能允许 BigQuery 用户查询表。

    • HMS_DB:如果您要将现有的 Hive Metastore 表复制到 BigLake Metastore,请指定 Hive Metastore 数据库。

    • HMS_TABLE:如果您要将现有 Hive Metastore 表复制到 BigLake Metastore,请指定 Hive Metastore 表。

    如需了解 Iceberg 目录配置,请参阅 Spark 目录

  5. 如需运行存储过程,请点击运行。如需了解详情,请参阅调用 Spark 存储过程。系统会在 BigQuery 中为 Iceberg 创建一个 BigLake 外部表。

使用元数据文件创建表

您可以使用 JSON 元数据文件为 Iceberg 创建 BigLake 外部表。但不建议使用这种方法,因为您必须手动更新 JSON 元数据文件的 URI 才能使 BigLake 表保持最新状态。如果 URI 未保持最新状态,BigQuery 中的查询可能会失败,或是导致提供的结果与直接使用 Iceberg 目录的查询引擎提供的结果不同。为了避免出现这种情况,请在创建 Iceberg BigLake 表时引用 BigLake Metastore 实例

系统将在您创建使用 Spark 的 Iceberg 表时指定的 Cloud Storage 存储桶中创建 Iceberg 表元数据文件。

从下列选项中选择一项:

SQL

使用 CREATE EXTERNAL TABLE 语句。 以下示例将创建一个名为 myexternal-table 的 BigLake 表:

  CREATE EXTERNAL TABLE myexternal-table
  WITH CONNECTION `myproject.us.myconnection`
  OPTIONS (
         format = 'ICEBERG',
         uris = ["gs://mybucket/mydata/mytable/metadata/iceberg.metadata.json"]
   )

uris 值替换为特定表快照的最新 JSON 元数据文件

您可以通过设置 require_partition_filter 标志来启用需要分区过滤条件

bq

在命令行环境中,将 bq mk --table 命令@connection 修饰器结合使用,指定要在 --external_table_definition 参数末尾使用的连接。如需启用需要分区过滤条件,请使用 --require_partition_filter

bq mk 
--table
--external_table_definition=TABLE_FORMAT=URI@projects/CONNECTION_PROJECT_ID/locations/CONNECTION_REGION/connections/CONNECTION_ID
PROJECT_ID:DATASET.EXTERNAL_TABLE

替换以下内容:

  • TABLE_FORMAT:要创建的表的格式

    在此示例中为 ICEBERG

  • URI:特定表快照的最新 JSON 元数据文件

    例如 gs://mybucket/mydata/mytable/metadata/iceberg.metadata.json

    URI 也可以指向外部云端位置,例如 Amazon S3 或 Azure Blob Storage。

    • AWS 示例:s3://mybucket/iceberg/metadata/1234.metadata.json
    • Azure 示例:azure://mystorageaccount.blob.core.windows.net/mycontainer/iceberg/metadata/1234.metadata.json
  • CONNECTION_PROJECT_ID:包含用于创建 BigLake 表的连接的项目,例如 myproject

  • CONNECTION_REGION:包含用于创建 BigLake 表的连接的区域,例如 us

  • CONNECTION_ID:表连接 ID,例如 myconnection

    当您在 Google Cloud 控制台中查看连接详情时,连接 ID 是连接 ID 中显示的完全限定连接 ID 的最后一部分中的值,例如 projects/myproject/locations/connection_location/connections/myconnection

  • DATASET:要在其中创建表的 BigQuery 数据集的名称

    例如 mydataset

  • EXTERNAL_TABLE:您要创建的表的名称

    例如 mytable

更新表元数据

如果您使用 JSON 元数据文件为 Iceberg 创建 BigLake 外部表,请将表定义更新为最新表元数据。如需更新架构或元数据文件,请选择以下任一方法:

bq

  1. 创建表定义文件:

    bq mkdef --source_format=ICEBERG \
    "URI" > TABLE_DEFINITION_FILE
    
  2. 使用带有 --autodetect_schema 标志的 bq update 命令

    bq update --autodetect_schema --external_table_definition=TABLE_DEFINITION_FILE
    PROJECT_ID:DATASET.TABLE
    

    替换以下内容:

    • URI:包含最新 JSON 元数据文件的 Cloud Storage URI

      例如 gs://mybucket/us/iceberg/mytable/metadata/1234.metadata.json

    • TABLE_DEFINITION_FILE:包含表架构的文件的名称

    • PROJECT_ID:要更新的表所属的项目的 ID

    • DATASET:包含要更新的表的数据集

    • TABLE:要更新的表

API

使用 tables.patch 方法,并将 autodetect_schema 属性设置为 true

PATCH https://bigquery.googleapis.com/bigquery/v2/projects/PROJECT_ID/datasets/DATASET/tables/TABLE?autodetect_schema=true

替换以下内容:

  • PROJECT_ID:要更新的表所属的项目的 ID
  • DATASET:包含要更新的表的数据集
  • TABLE:要更新的表

在请求正文中,为以下字段指定更新后的值:

{
     "externalDataConfiguration": {
      "sourceFormat": "ICEBERG",
      "sourceUris": [
        "URI"
      ]
    },
    "schema": null
  }'

URI 替换为最新的 Iceberg 元数据文件。例如 gs://mybucket/us/iceberg/mytable/metadata/1234.metadata.json

设置访问权限控制政策

您可以使用多种方法来控制对 BigLake 表的访问权限:

例如,假设您要限制数据集 mydataset 中表 mytable 的行访问权限:

+---------+---------+-------+
| country | product | price |
+---------+---------+-------+
| US      | phone   |   100 |
| JP      | tablet  |   300 |
| UK      | laptop  |   200 |
+---------+---------+-------+

您可以为 Kim (kim@example.com) 创建行级过滤条件,限制其仅可访问 countryUS 的行。

CREATE ROW ACCESS POLICY only_us_filter
ON mydataset.mytable
GRANT TO ('user:kim@example.com')
FILTER USING (country = 'US');

之后,Kim 运行以下查询:

SELECT * FROM projectid.mydataset.mytable;

输出将仅显示 countryUS 的行:

+---------+---------+-------+
| country | product | price |
+---------+---------+-------+
| US      | phone   |   100 |
+---------+---------+-------+

查询 BigLake 表

如需了解详情,请参阅查询 Iceberg 数据

数据映射

BigQuery 会将 Iceberg 数据类型转换为 BigQuery 数据类型,如下表所示:

Iceberg 数据类型 BigQuery 数据类型
boolean BOOL
int INT64
long INT64
float FLOAT64
double FLOAT64
Decimal(P/S) NUMERIC or BIG_NUMERIC depending on precision
date DATE
time TIME
timestamp DATETIME
timestamptz TIMESTAMP
string STRING
uuid BYTES
fixed(L) BYTES
binary BYTES
list<Type> ARRAY<Type>
struct STRUCT
map<KeyType, ValueType> ARRAY<Struct<key KeyType, value ValueType>>

限制

除了 BigLake 表限制之外,Iceberg BigLake 表还具有以下限制:

  • 支持 copy-on-write 配置,但不支持 merge-on-read 配置。如需了解详情,请参阅 Iceberg 配置

  • BigQuery 支持使用所有 Iceberg 分区转换函数进行清单删减,但 Bucket 除外。如需了解如何删减分区,请参阅查询分区表。与分区列相比,引用 Iceberg 的 BigLake 外部表的查询必须在谓词中包含字面量。

  • 仅支持 Apache Parquet 数据文件。

  • 如果您使用的是 BigLake Metastore,则存在以下限制:

    • BigQuery Omni 区域不支持 BigLake Metastore。
    • 重命名表时,目标表必须与源表位于同一数据库中。必须明确指定目标表的数据库。
    • 检查 Iceberg 元数据表时,您必须使用完全限定的表名称。例如 prod.db.table.history

费用

对于向 BigLake Metastore 发起的每 6,250,000 个请求以及存储在 BigLake Metastore 中的每 625,000 个对象,您将按需(每 TB)查询定价支付 1 TB 的费用。按需查询价格因区域而异。对于少量请求或对象,您需要支付 1 TB 的适当费用。

例如,如果您向 BigLake Metastore 发出了 6,250,000 个请求并在其中存储了 312,500 个对象,则将按照创建 BigLake Metastore 实例所在区域的按需查询价格费率支付 1.5 TB 的费用。

需要分区过滤条件

您可以通过为 Iceberg 表启用需要分区过滤条件选项来要求使用谓词过滤条件。如果启用此选项,则尝试在未指定与每个清单文件一致的 WHERE 子句的情况下查询表会产生以下错误:

Cannot query over table project_id.dataset.table without a
filter that can be used for partition elimination.

每个清单文件都需要至少一个适合分区消除的谓词。

在创建 Iceberg 表时,您可以通过以下方式启用 require_partition_filter

SQL

使用 CREATE EXTERNAL TABLE 语句。以下示例会创建一个启用了需要分区过滤条件的 BigLake 表,名为 TABLE

  CREATE EXTERNAL TABLE TABLE
  WITH CONNECTION `PROJECT_ID.REGION.CONNECTION_ID`
  OPTIONS (
         format = 'ICEBERG',
         uris = [URI],
         require_partition_filter = true
   )

替换以下内容:

  • TABLE:您要创建的表的名称。
  • PROJECT_ID:包含您要创建的表的项目的 ID。
  • REGION:您要在其中创建 Iceberg 表的位置
  • CONNECTION_ID连接 ID。例如 myconnection

  • URI:包含最新 JSON 元数据文件的 Cloud Storage URI。

    例如 gs://mybucket/us/iceberg/mytable/metadata/1234.metadata.json

    URI 也可以指向外部云端位置,例如 Amazon S3 或 Azure Blob Storage。

    • AWS 示例:s3://mybucket/iceberg/metadata/1234.metadata.json
    • Azure 示例:azure://mystorageaccount.blob.core.windows.net/mycontainer/iceberg/metadata/1234.metadata.json

bq

bq mk --table 命令@connection 修饰器结合使用,指定要在 --external_table_definition 参数末尾使用的连接。使用 --require_partition_filter 启用需要分区过滤条件。以下示例会创建一个启用了需要分区过滤条件的 BigLake 表,名为 TABLE

bq mk \
    --table \
    --external_table_definition=ICEBERG=URI@projects/CONNECTION_PROJECT_ID/locations/CONNECTION_REGION/connections/CONNECTION_ID \
    PROJECT_ID:DATASET.EXTERNAL_TABLE \
    --require_partition_filter

替换以下内容:

  • URI:特定表快照的最新 JSON 元数据文件

    例如 gs://mybucket/mydata/mytable/metadata/iceberg.metadata.json

    URI 也可以指向外部云端位置,例如 Amazon S3 或 Azure Blob Storage。

    • AWS 示例:s3://mybucket/iceberg/metadata/1234.metadata.json
    • Azure 示例:azure://mystorageaccount.blob.core.windows.net/mycontainer/iceberg/metadata/1234.metadata.json
  • CONNECTION_PROJECT_ID:包含用于创建 BigLake 表的连接的项目,例如 myproject

  • CONNECTION_REGION:包含用于创建 BigLake 表的连接的区域。例如 us

  • CONNECTION_ID连接 ID。例如 myconnection

    当您在 Google Cloud 控制台中查看连接详情时,连接 ID 是连接 ID 中显示的完全限定连接 ID 的最后一部分中的值,例如 projects/myproject/locations/connection_location/connections/myconnection

  • DATASET:包含您要更新的表的

    BigQuery 数据集的名称。例如 mydataset

  • EXTERNAL_TABLE:要创建的表的名称

    例如 mytable

您还可以更新 Iceberg 表以启用需要分区过滤条件。

如果您在创建分区表时未启用需要分区过滤条件选项,则可以更新表来添加该选项。

bq

使用 bq update 命令并提供 --require_partition_filter 标志。

例如:

如需更新默认项目中 mydatasetmypartitionedtable,请输入以下命令:

bq update --require_partition_filter PROJECT_ID:DATASET.TABLE

后续步骤