通过 Snowflake Horizon 目录使用外部引擎访问 Apache Iceberg™ 表

通过 Snowflake Horizon 目录使用外部查询引擎,访问 Snowflake 托管的 Apache Iceberg™ 表。为了确保与外部引擎的互操作性,`Apache Polaris™<https://github.com/apache/polaris>`_ 已集成到 Horizon 目录中。此外,Horizon 目录还提供了 Apache Iceberg™ REST API(Horizon Iceberg REST 目录 API)。此 API 允许您使用外部查询引擎访问表。

您可以使用 Horizon 目录(在所有现有 Snowflake 账户中都可用),通过外部查询引擎读取和写入 Snowflake 托管的 Iceberg 表。通过使用 Horizon 目录,您无需通过 Snowflake Open Catalog 同步 Snowflake 托管的 Iceberg 表,也无需创建单独的 Snowflake Open Catalog 账户,即可使用外部查询引擎访问 Snowflake 托管的 Iceberg 表。

查询 Iceberg 表

通过 Horizon 目录将外部查询引擎连接到 Iceberg 表,您可以执行以下任务:

  • 使用任何支持开放 Iceberg REST 协议的外部查询引擎(例如 Apache Spark™)查询这些表。

  • 使用单个 Horizon 目录端点,查询新的或现有的 Snowflake 账户中任何现有和新的 Snowflake 托管的 Iceberg 表。

  • 使用 Snowflake 中的现有用户、角色、策略和身份验证来查询表。

  • 使用分发的凭据。

有关 Snowflake Horizon 目录的更多信息,请参阅 Snowflake Horizon 目录

写入 Iceberg 表

通过 Horizon 目录使用外部查询引擎写入 Iceberg 表的功能现已推出公开预览版。要写入表,请按照 使用外部查询引擎访问 Iceberg 表的工作流程 操作。配置访问控制时,请确保 配置对表的写入权限

然后 写入 Iceberg 表

下图显示了外部查询引擎通过 Horizon 目录读取和写入 Snowflake 托管的 Iceberg 表,以及 Snowflake 对这些表的读取和写入:

该图显示了外部查询引擎通过 Horizon 目录读取 Snowflake 托管的 Iceberg 表,以及 Snowflake 读取和 写入这些表。

计费

  • Horizon Iceberg REST 目录 API 适用于所有 Snowflake 版本。

  • API 请求按每百万次调用 0.5 Credit 计费,并作为云服务进行收费。

  • 对于跨区域数据访问,将适用 Snowflake 服务消耗表 中的标准跨区域数据出口费。

备注

此功能计划于 2026 年年中开始计费,具体情况可能会有变。

支持的外部引擎和目录

下表虽然并不详尽,但显示了与 Horizon Iceberg REST 目录 API 集成的外部引擎和目录。此集成使外部系统能够访问 Snowflake 管理的 Iceberg 表。

支持的外部引擎

以下外部查询引擎可与 Horizon Iceberg REST 目录 API 集成:

产品

通过 Horizon 目录访问 Snowflake 管理的 Iceberg 表

Apache Doris™

Apache Flink™

Apache Spark

Dremio

DuckDB

PyIceberg

StarRocks

Trino

支持的外部目录

以下外部目录可与 Horizon Iceberg REST 目录 API 集成:

产品

通过 Horizon 目录访问 Snowflake 管理的 Iceberg 表

注释

Apache Polaris™

AWS Glue

有关如何配置此集成的说明,请参阅 AWS 大数据博客中的 使用目录联合通过 AWS Glue Data Catalog 访问 Snowflake Horizon 目录数据 (https://aws.amazon.com/blogs/big-data/access-snowflake-horizon-catalog-data-using-catalog-federation-in-the-aws-glue-data-catalog/)。

Palantir Foundry

有关如何配置此集成的说明,请参阅 Palantir 文档中的 `Iceberg 表(仅限虚拟表)<https://www.palantir.com/docs/foundry/available-connectors/snowflake#iceberg-tables-virtual-tables-only>`_

Databricks Unity 目录

未公布

Google BigLake Metastore

开发中

Microsoft Fabric / Synapse

开发中

先决条件

检索包含要访问的 Iceberg 表的 Snowflake 的账户账户标识符。有关说明,请参阅 账户标识符。您可以在 将外部查询引擎连接到 Iceberg 表 时指定此标识符。

小技巧

要获取您的账户标识符,请使用 SQL,您可以运行以下命令:

SELECT CURRENT_ORGANIZATION_NAME() || '-' || CURRENT_ACCOUNT_NAME();

(可选)专用连接

为确保安全连接,建议在访问 Horizon Catalog 端点时,为您的 Snowflake 账户配置 入站出站 专用连接。

备注

专用连接仅支持存储在 Amazon S3 或 Azure 存储 (ADLS) 中的由 Snowflake 管理的 Iceberg 表。

使用外部查询引擎访问 Iceberg 表的工作流程

要使用外部查询引擎访问 Iceberg 表,请完成以下步骤:

  1. 创建 Iceberg 表

  2. 配置访问控制

  3. 获取用于身份验证的访问令牌

  4. 验证访问令牌权限

  5. (可选)配置数据保护策略

  6. 通过 Horizon 目录将外部查询引擎连接到 Iceberg 表

  7. 查询 Iceberg 表写入 Iceberg 表

第 1 步:创建 Iceberg 表

重要

如果您已经拥有要访问的 Snowflake 托管的 Iceberg 表,则可以跳过此步骤。

在此步骤中,您将创建 Snowflake 托管的 Iceberg 表,这些表使用 Snowflake 作为目录,从而支持通过外部查询引擎访问这些表。有关说明,请参阅以下主题:

第 2 步:配置访问控制

重要

如果您已经配置具备访问目标 Iceberg 表权限的角色,则可以跳过此步骤。

在此步骤中,您将为要使用外部查询引擎访问的 Snowflake 托管的 Iceberg 表配置访问控制。例如,您可以在 Snowflake 中设置以下角色:

  • data_engineer 角色,该角色有权访问数据库中的所有架构和所有 Snowflake 托管的 Iceberg 表。

  • data_analyst 角色,该角色可以访问数据库中的一个架构,但只能访问该架构内的两个 Snowflake 托管的 Iceberg 表。

有关更多信息,请参阅以下部分:

配置对 Iceberg 表的读取权限

要查询 Iceberg 表,执行该操作的角色必须拥有 Iceberg 表的 SELECT 权限,以及父数据库和架构的 USAGE 权限。有关如何向角色授予这些权限的示例,请参阅 示例:设置服务账户用户

重要

具有 Iceberg 表 OWNERSHIP 权限的角色必须保有与表关联的外部卷的 USAGE 权限。如果所有者角色没有外部卷的 USAGE,则任何要求提供分发凭据的读取或写入表操作都将失败。

示例:设置服务账户用户

以下示例在 Snowflake 中设置了一个服务账户用户,该用户对 Iceberg 表具有只读访问权限:

  • 创建一个 data_engineer 角色。

  • 授予 data_engineer 角色对 iceberg_test_db 数据库及其 public 架构的 USAGE 和 MONITOR 权限。

  • 授权对 test_table Iceberg 表的 SELECT 权限。

  • 创建名为 horizon_rest_srv_account_user 的服务用户并为该用户分配 data_engineer 角色。

CREATE OR REPLACE ROLE data_engineer;

GRANT USAGE ON DATABASE iceberg_test_db TO ROLE data_engineer;
GRANT USAGE ON SCHEMA iceberg_test_db.public TO ROLE data_engineer;

GRANT SELECT ON TABLE iceberg_test_db.public.test_table TO ROLE data_engineer;

CREATE OR REPLACE USER horizon_rest_srv_account_user TYPE=SERVICE DEFAULT_ROLE=data_engineer;

GRANT ROLE data_engineer TO USER horizon_rest_srv_account_user;

(可选)在 Iceberg 表上应用未来授权

为了确保能够访问架构中创建的任何新 Iceberg 表,请使用 GRANT … ON FUTURE ICEBERG TABLES 语法。

以下示例授予 data_engineer 角色对在名为 my_schema 的模式下创建的任何 Iceberg 表的访问权限。

GRANT SELECT ON FUTURE ICEBERG TABLES IN SCHEMA my_db.my_schema TO ROLE data_engineer;

有关 Snowflake 中访问控制的更多信息,请参阅以下主题:

配置对 Iceberg 表的写入权限

下表描述了对 Iceberg 表执行写入操作所需的权限:

操作

必要的权限

数据操作语言 (DML) 操作

重要

用于执行操作的角色必须具有以下 所有 权限:

  • 表的 SELECT、UPDATE、TRUNCATE、INSERT 和 DELETE 权限

  • 嵌套表的父架构的 USAGE 权限

  • 嵌套表的父数据库或架构的 USAGE 权限

CREATE ICEBERG TABLE

用于执行操作的角色必须具有以下权限:

  • 架构的 CREATE ICEBERG TABLE 权限

  • 外部卷的 USAGE 权限

CREATE SCHEMA

用于执行操作的角色必须具有父数据库的 CREATE SCHEMA 权限。

重命名表

用于执行操作的角色必须具有表的 OWNERSHIP 权限。

重要

要将表移动到新架构,请确保您的角色还具有目标架构的 CREATE ICEBERG TABLE 权限。

表上的所有其他操作

除了架构和数据库的权限之外,用于执行操作的角色还必须具有表的 OWNERSHIP 权限。例如,您必须具有这些权限才能运行 ALTER ICEBERG TABLE … ADD COLUMN 或 ALTER ICEBERG TABLE … DROP COLUMN 操作。

有关 Snowflake 中访问控制的更多信息,请参阅以下主题:

第 3 步:获取用于身份验证的访问令牌

在此步骤中,您将获得一个访问令牌,您必须使用该令牌对 Snowflake 账户的 Horizon 目录端点进行身份验证。您需要为配置为可以访问 Snowflake 托管的 Iceberg 表的每个用户(服务或人员)和角色获取访问令牌。例如,您需要为具有 DATA_ENGINEER 角色的用户获取一个访问令牌,并为具有另一个 DATA_ANALYST 角色的用户再获取一个访问令牌。

稍后,当您 通过 Horizon 目录将外部查询引擎连接到 Iceberg 表 时,需要指定该访问令牌。

您可以使用以下身份验证选项之一获取访问令牌:

External OAuth

如果您使用的是外部 OAuth,请为身份提供商生成访问令牌。有关说明,请参阅 External OAuth 概览

备注

对于外部 OAuth,您还可以使用自动令牌刷新配置与引擎的连接,而不是指定访问令牌。

密钥对身份验证

如果您使用密钥对身份验证,且要获取访问令牌,您需要使用私钥签署 JSON 网络令牌 (JWT)。

以下步骤介绍如何生成用于密钥对身份验证的访问令牌:

  1. 配置密钥对身份验证

  2. 向用户授予角色

  3. 生成 JSON Web 令牌 (JWT)

  4. 生成访问令牌

第 1 步:配置密钥对身份验证

在此步骤中,您需要执行以下任务:

  • 生成私钥

  • 生成公钥

  • 安全地存储私钥和公​​钥

  • 授予向 Snowflake 用户分配公钥的权限

  • 将公钥分配给 Snowflake 用户

  • 验证用户的公钥指纹

有关说明,请参阅 配置密钥对身份验证

第 2 步:向用户授予角色

要将具有访问目标表权限的 Snowflake 角色授予密钥对身份验证用户,请运行 GRANT ROLE 命令。例如,要向 my_service_user 用户授予 ENGINEER 角色,请运行以下命令:

GRANT ROLE ENGINEER to user my_service_user;

第 3 步:生成 JSON Web 令牌 (JWT)

在此步骤中,您将使用 SnowSQL 生成用于密钥对身份验证的 JSON Web 令牌 (JWT)。

备注

使用 SnowSQL 生成 JWT:

snowsql --private-key-path "<private_key_file>" \
  --generate-jwt \
  -h "<account_identifier>.snowflakecomputing.cn" \
  -a "<account_locator>" \
  -u "<user_name>"

其中:

  • <private_key_file> is the path to your private key file that corresponds to the public key assigned to your Snowflake user.For example: /Users/jsmith/.ssh/rsa_key.p8.

  • <account_identifier> 是您的 Snowflake 账户的账户标识符,格式为 <organization_name>-<account_name>。要查找账户标识符,请参阅 支持的外部引擎和目录。账户标识符示例:myorg-myaccount

  • <account_locator> 是 Snowflake 账户的账户定位器。

    要查找您的账户定位器,请参阅 在 Snowsight 中查找您的 Snowflake 账户信息,并并在 Account Details 对话框中查看 账户定位器

  • <user_name> 是 Snowflake 用户的用户名,且该用户已获分配公钥。

第 4 步:生成访问令牌

重要

要生成访问令牌,您必须先 生成一个 JWT。之所以需要先生成 JWT,是因为访问令牌正是基于 JWT 生成的。

使用命令 curl 生成访问令牌:

curl -i --fail -X POST "https://<account_identifier>.snowflakecomputing.cn/polaris/api/catalog/v1/oauth/tokens" \
 --header 'Content-Type: application/x-www-form-urlencoded' \
 --data-urlencode 'grant_type=client_credentials' \
 --data-urlencode 'scope=session:role:<role>' \
 --data-urlencode 'client_secret=<JWT_token>'

其中:

  • <account_identifier> 是您的 Snowflake 账户的账户标识符,格式为 <organization_name>-<account_name>。要查找账户标识符,请参阅 支持的外部引擎和目录。账户标识符示例:myorg-myaccount

  • <role> 是授予访问 Iceberg 表权限的 Snowflake 角色,例如 ENGINEER。

  • <JWT_token> 是您在上一步中生成的 JWT。

编程访问令牌 (PAT)

如果您使用 PATs,则生成用于身份验证的 PAT。

首先,生成一个 PAT,用于 将外部查询引擎连接到 Iceberg 表。然后生成访问令牌,仅用于验证您的 PAT 的权限。

第 1 步:生成 PAT

有关如何配置和生成 PAT,请参阅 用于身份验证的编程访问令牌

以下示例将为上一步骤中创建的服务账户用户生成程序化访问令牌 (PAT),使用 ALTER USER ... ADD PROGRAMMATIC ACCESS TOKEN (PAT) 命令:

ALTER USER IF EXISTS HORIZON_REST_SRV_ACCOUNT_USER
ADD PAT HORIZON_REST_SRV_ACCOUNT_USER_PAT
  DAYS_TO_EXPIRY = 7
  ROLE_RESTRICTION = 'DATA_ENGINEER'
  COMMENT = 'HORIZON REST API PAT FOR SERVICE ACCOUNT';

第 2 步:为 PAT 生成访问令牌

在此步骤中,将为 PAT 生成访问令牌。

注意

仅在为 PAT 验证权限 时,需提供本步骤生成的访问令牌。将外部查询引擎连接至 Iceberg 表 时,必须指定上一步骤生成的 PAT,而非本步骤生成的访问令牌。

使用 curl 命令为 PAT 生成访问令牌:

curl -i --fail -X POST "https://<account_identifier>.snowflakecomputing.cn/polaris/api/catalog/v1/oauth/tokens" \
 --header 'Content-Type: application/x-www-form-urlencoded' \
 --data-urlencode 'grant_type=client_credentials' \
 --data-urlencode 'scope=session:role:<role>' \
 --data-urlencode 'client_secret=<PAT_token>'

其中:

  • <account_identifier> 是您的 Snowflake 账户的账户标识符,格式为 <organization_name>-<account_name>。要查找账户标识符,请参阅 支持的外部引擎和目录。账户标识符示例:myorg-myaccount

  • <role> 是授予您 PAT 的 Snowflake 角色,该角色可访问您要查询或写入的 Iceberg 表,例如 ENGINEER。

  • <PAT_token> 是您在上一步骤生成的 PAT 值。

第 4 步:验证访问令牌权限

在此步骤中,您将验证在上一步中获取的访问令牌的权限。

验证对 Horizon IRC 端点的访问权限

使用 curl 命令验证您是否具有访问 Horizon IRC 端点的权限:

curl -i --fail -X GET "https://<account_identifier>.snowflakecomputing.cn/polaris/api/catalog/v1/config?warehouse=<database_name>" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json"

其中:

  • <account_identifier> 是您的 Snowflake 账户的账户标识符,格式为 <organization_name>-<account_name>。要查找账户标识符,请参阅 支持的外部引擎和目录。账户标识符示例:myorg-myaccount

  • <access_token> 是您生成的访问令牌。若使用 PAT,此值应为 生成的访问令牌,而非您生成的 个人访问令牌 (PAT)

  • <database_name> 是包含要访问的 Iceberg 表的数据库的名称。

    重要

    如果创建数据库时名称周围没有引号,则必须使用 全部大写字母 指定数据库名称,即使它是使用小写字母创建的。

返回值示例:

{
  "defaults": {
    "default-base-location": ""
  },
  "overrides": {
    "prefix": "MY-DATABASE"
  }
}

检索表的元数据

您还可以通过 GET 请求检索表的元数据。Snowflake 使用 loadTable (https://github.com/apache/iceberg/blob/apache-iceberg-1.6.1/open-api/rest-catalog-open-api.yaml#L616) 操作从您的 REST 目录加载表元数据。

curl -i --fail -X GET "https://<account_identifier>.snowflakecomputing.cn/polaris/api/catalog/v1/<database_name>/namespaces/<namespace_name>/tables/<table_name>" \
 -H "Authorization: Bearer <access_token>" \
 -H "Content-Type: application/json"

其中:

  • <account_identifier> 是您的 Snowflake 账户的账户标识符,格式为 <organization_name>-<account_name>。要查找账户标识符,请参阅 支持的外部引擎和目录。账户标识符示例:myorg-myaccount

  • <database_name> 是要检索其元数据的表的数据库。

  • <namespace_name> 是要检索其元数据的表的命名空间。

  • <table_name> 是要检索其元数据的表。

  • <access_token> 是您生成的访问令牌。若使用 PAT,此值应为 生成的访问令牌,而非您生成的 个人访问令牌 (PAT)

重要

如果创建数据库、命名空间或表时名称周围没有引号,则必须使用 全部大写字母 指定数据库、命名空间或表名称,即使对象是使用小写字母创建的。

(可选)第 5 步:配置数据保护策略

在此步骤中,为 Iceberg 表配置数据保护策略。如果没有需要使用 Snowflake 数据策略保护的表,可以继续执行下一步。

备注

受数据保护策略保护的表可通过 Horizon Iceberg RESTAPI 或使用 Apache Spark™ 访问。

有关配置数据保护策略的说明,请参阅 在通过 Horizon Iceberg REST API 访问的 Iceberg 表上配置数据保护策略并使用 Apache Spark™

第 6 步:通过 Horizon 目录将外部查询引擎连接到 Iceberg 表

在此步骤中,您将通过 Horizon 目录将外部查询引擎连接到 Iceberg 表。通过此连接,您可以使访问表。

外部引擎使用 Snowflake 公开的 Apache Iceberg™ REST 端点。对于您的 Snowflake 账户,此端点采用以下格式:

https://<account_identifier>.snowflakecomputing.cn/polaris/api/catalog

此步骤中的示例代码展示了如何在 Spark 中设置连接,示例代码则位于 PySpark。有关更多信息,请参阅以下部分:

使用外部 OAuth 或密钥对身份验证进行连接

使用以下配置之一进行连接:

在不强制执行数据策略的情况下连接外部查询引擎

  • 使用外部 OAuth 或密钥对身份验证将外部查询引擎连接到 Iceberg 表。使用以下示例代码。

此代码不强制执行数据保护策略:

# Snowflake Horizon Catalog Configuration, change as per your environment

CATALOG_URI = "https://<account_identifier>.snowflakecomputing.cn/polaris/api/catalog"
HORIZON_SESSION_ROLE = f"session:role:<role>"
CATALOG_NAME = "<database_name>" #provide in UPPER CASE

# Cloud Service Provider Region Configuration (where the Iceberg data is stored)
REGION = "eastus2"

# Paste the External Oauth Access token that you generated in Snowflake here
ACCESS_TOKEN = "<your_access_token>"

# Iceberg Version
ICEBERG_VERSION = "1.9.1"

def create_spark_session():
  """Create and configure Spark session for Snowflake Iceberg access."""
  spark = (
      SparkSession.builder
      .appName("SnowflakeIcebergReader")
      .master("local[*]")

# JAR Dependencies for Iceberg and Azure
      .config(
          "spark.jars.packages",
          f"org.apache.iceberg:iceberg-spark-runtime-3.5_2.12:{ICEBERG_VERSION},"
          f"org.apache.iceberg:iceberg-aws-bundle:{ICEBERG_VERSION}"
          # for Azure storage, use the below package and comment above azure bundle
          # f"org.apache.iceberg:iceberg-azure-bundle:{ICEBERG_VERSION}"
      )

      # Iceberg SQL Extensions
      .config("spark.sql.extensions", "org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions")
      .config("spark.sql.defaultCatalog", CATALOG_NAME)

      # Horizon REST Catalog Configuration
      .config(f"spark.sql.catalog.{CATALOG_NAME}", "org.apache.iceberg.spark.SparkCatalog")
      .config(f"spark.sql.catalog.{CATALOG_NAME}.type", "rest")
      .config(f"spark.sql.catalog.{CATALOG_NAME}.uri", CATALOG_URI)
      .config(f"spark.sql.catalog.{CATALOG_NAME}.warehouse", CATALOG_NAME)
      .config(f"spark.sql.catalog.{CATALOG_NAME}.token", ACCESS_TOKEN)
      .config(f"spark.sql.catalog.{CATALOG_NAME}.scope", HORIZON_SESSION_ROLE)
      .config(f"spark.sql.catalog.{CATALOG_NAME}.client.region", REGION)

      # Required for vended credentials
      .config(f"spark.sql.catalog.{CATALOG_NAME}.header.X-Iceberg-Access-Delegation", "vended-credentials")
      .config("spark.sql.iceberg.vectorization.enabled", "false")
      .getOrCreate()
  )
  spark.sparkContext.setLogLevel("ERROR")
  return spark

其中:

  • <account_identifier> 是包含要访问的 Iceberg 表的 Snowflake 账户的 Snowflake 账户标识符。要查找此标识符,请参阅 支持的外部引擎和目录

  • <your_access_token> 是您获得的访问令牌。要获取该令牌,请参阅 第 3 步:获取用于身份验证的访问令牌

    备注

    对于外部 OAuth,您还可以使用自动令牌刷新配置与引擎的连接,而不是指定访问令牌。

  • <database_name> 是 Snowflake 账户中数据库的名称,该数据库包含您要访问的 Snowflake 托管的 Iceberg 表。

    备注

    Spark 中的 .warehouse 属性需要 Snowflake 数据库 名称,而不是 Snowflake 仓库名称。

  • <role> 是 Snowflake 中配置为对要访问的 Iceberg 表具有访问权限的角色。例如:DATA_ENGINEER。

重要

默认情况下,代码示例是针对存储在 Amazon S3 上的 Apache Iceberg™ 表进行设置的。如果您的 Iceberg 表存储在 Azure 存储 (ADLS) 中,请执行以下步骤:

  1. 注释以下行:f"org.apache.iceberg:iceberg-aws-bundle:{ICEBERG_VERSION}"

  2. 取消注释以下行:# f"org.apache.iceberg:iceberg-azure-bundle:{ICEBERG_VERSION}"

连接外部查询引擎并强制执行数据策略

使用编程访问令牌 (PAT) 进行连接

使用以下配置之一进行连接:

在不强制执行数据策略的情况下连接外部查询引擎

  • 使用以下示例代码,通过编程访问令牌 (PAT) 将外部查询引擎连接到 Iceberg 表:

此代码不强制执行数据保护策略:

# Snowflake Horizon Catalog Configuration, change as per your environment

CATALOG_URI = "https://<account_identifier>.snowflakecomputing.cn/polaris/api/catalog"
HORIZON_SESSION_ROLE = f"session:role:<role>"
CATALOG_NAME = "<database_name>" #provide in UPPER CASE

# Cloud Service Provider Region Configuration (where the Iceberg data is stored)
REGION = "eastus2"

# Paste the PAT you generated in Snowflake here
PAT_TOKEN = "<your_PAT_token>"

# Iceberg Version
ICEBERG_VERSION = "1.9.1"

def create_spark_session():
  """Create and configure Spark session for Snowflake Iceberg access."""
  spark = (
      SparkSession.builder
      .appName("SnowflakeIcebergReader")
      .master("local[*]")

# JAR Dependencies for Iceberg and Azure
      .config(
          "spark.jars.packages",
          f"org.apache.iceberg:iceberg-spark-runtime-3.5_2.12:{ICEBERG_VERSION},"
          f"org.apache.iceberg:iceberg-aws-bundle:{ICEBERG_VERSION}"
          # for Azure storage, use the below package and comment above azure bundle
          # f"org.apache.iceberg:iceberg-azure-bundle:{ICEBERG_VERSION}"
      )

      # Iceberg SQL Extensions
      .config("spark.sql.extensions", "org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions")
      .config("spark.sql.defaultCatalog", CATALOG_NAME)

      # Horizon REST Catalog Configuration
      .config(f"spark.sql.catalog.{CATALOG_NAME}", "org.apache.iceberg.spark.SparkCatalog")
      .config(f"spark.sql.catalog.{CATALOG_NAME}.type", "rest")
      .config(f"spark.sql.catalog.{CATALOG_NAME}.uri", CATALOG_URI)
      .config(f"spark.sql.catalog.{CATALOG_NAME}.warehouse", CATALOG_NAME)
      .config(f"spark.sql.catalog.{CATALOG_NAME}.credential", PAT_TOKEN)
      .config(f"spark.sql.catalog.{CATALOG_NAME}.scope", HORIZON_SESSION_ROLE)
      .config(f"spark.sql.catalog.{CATALOG_NAME}.client.region", REGION)

      # Required for vended credentials
      .config(f"spark.sql.catalog.{CATALOG_NAME}.header.X-Iceberg-Access-Delegation", "vended-credentials")
      .config("spark.sql.iceberg.vectorization.enabled", "false")
      .getOrCreate()
  )
  spark.sparkContext.setLogLevel("ERROR")
  return spark

其中:

  • <account_identifier> 是包含要访问的 Iceberg 表的 Snowflake 账户的 Snowflake 账户标识符。要查找此标识符,请参阅 支持的外部引擎和目录

  • <your_PAT_token> 是您获取的 PAT。要获取该令牌,请参阅 第 3 步:获取用于身份验证的访问令牌

  • <role> 是 Snowflake 中配置为对要访问的 Iceberg 表具有访问权限的角色。例如:DATA_ENGINEER。

  • <database_name> 是 Snowflake 账户中数据库的名称,该数据库包含您要访问的 Snowflake 托管的 Iceberg 表。

    备注

    Spark 中的 .warehouse 属性需要 Snowflake 数据库 名称,而不是 Snowflake 仓库名称。

重要

默认情况下,代码示例是针对存储在 Amazon S3 上的 Apache Iceberg™ 表进行设置的。如果您的 Iceberg 表存储在 Azure 存储 (ADLS) 中,请执行以下步骤:

  1. 注释以下行:f"org.apache.iceberg:iceberg-aws-bundle:{ICEBERG_VERSION}"

  2. 取消注释以下行:# f"org.apache.iceberg:iceberg-azure-bundle:{ICEBERG_VERSION}"

连接外部查询引擎并强制执行数据策略

第 7 步:访问 Iceberg 表

本部分包括使用 Apache Spark™ 查询和写入 Iceberg 表的代码示例。

查询 Iceberg 表

本部分提供了使用 Apache Spark™ 查询 Iceberg 表的以下代码示例:

  • 显示命名空间

  • 使用命名空间

  • 显示表

  • 查询表

显示命名空间

spark.sql("show namespaces").show()

使用命名空间

spark.sql("use namespace <your_schema_name_in_snowflake>")

显示表

spark.sql("show tables").show()

查询表

spark.sql("use namespace spark_demo")
spark.sql("select * from <your_table_name_in_snowflake>").show()

写入 Iceberg 表

本部分提供了使用 Apache Spark™ 写入 Iceberg 表的以下代码示例:

  • CREATE TABLE

  • INSERT INTO <table>

  • ALTER TABLE ... ADD COLUMN

  • UPDATE TABLE ...WHERE

  • DELETE TABLE ...WHERE

  • TRUNCATE TABLE

  • RENAME TABLE

  • DROP TABLE

CREATE TABLE

spark.sql("CREATE TABLE MY_TABLE (COLUMN1 INT) USING ICEBERG").show();

INSERT INTO <table>

spark.sql("INSERT INTO MY_TABLE VALUES (600)").show()

ALTER TABLE ... ADD COLUMN

spark.sql("ALTER TABLE MY_TABLE ADD COLUMN COLUMN2 INT").show()

UPDATE TABLE ...WHERE

spark.sql("UPDATE MY_TABLE SET COLUMN2 = 10 WHERE COLUMN1 = 100").show()

DELETE TABLE ...WHERE

spark.sql("DELETE FROM MY_TABLE WHERE COLUMN2 = 10").show()

TRUNCATE TABLE

spark.sql("TRUNCATE TABLE MY_TABLE").show()

RENAME TABLE

spark.sql("ALTER TABLE MY_TABLE RENAME TO MY_NEW_TABLE")

DROP TABLE

spark.sql("DROP TABLE MY_TABLE")

使用外部查询引擎访问 Iceberg 表的注意事项

本部分列出了使用外部查询引擎访问、查询和写入 Iceberg 表的注意事项。

使用外部查询引擎访问 Iceberg 表时,请注意以下事项:

  • Iceberg

    • 对于 Snowflake 中的表:

      • 仅支持 Snowflake 托管的 Iceberg 表。

  • 列表:

    • 通过 列表的自动履行 共享的 Iceberg 表无法通过使用者账户的 Horizon Iceberg REST 目录 API 访问。

  • 网络和专用连接:

    • 此功能不支持使用在用户级别设置的网络策略。

    • 对于 Snowflake 管理的网络规则,静态出口 IP 地址不受支持。

    • 不支持显式授予 Horizon 目录端点对存储账户的访问权限。我们建议使用专用连接,以确保从外部引擎到 Horizon 目录,以及从 Horizon 目录到存储账户的连接安全。

  • 云:

    • 商业:此功能仅支持存储在 Amazon S3、Google Cloud 或 Microsoft Azure 上,由 Snowflake 托管的 Iceberg 表,并适用于所有商业云区域。与 S3 兼容的非 AWS 存储尚不受支持。

    • FedRAMP(中等):Snowflake 托管的 Iceberg 表支持此功能,这些表存储在 AWS Commercial Gov (US) 的 FedRAMP(中等)部署环境中,区域为 us-east-1 和 us-west-2。

    • 对于存储在 Amazon S3 上的 Iceberg 表:

      • 如果您想使用 SSE-KMS 加密,请联系客户支持或您的客户团队,以获取有关启用访问权限的帮助。

        备注

        不支持写入使用 KMS 加密的外部卷。

    • 对于存储在 Azure 上的 Iceberg 表:

      • Azure 虚拟网络 (VNet) 不受支持。

  • 身份验证:

    • 对于密钥对身份验证,密钥对轮换不受支持。

    • 此功能不支持工作负载身份联合。

使用外部查询引擎查询(读取)Iceberg 表时,请注意以下事项:

  • Iceberg

    • 不支持查询以下表:

      • 远程表

      • Snowflake 原生表

      • 外部管理的 Iceberg 表,包括基于 Delta 的 Iceberg 表和由 Snowflake 管理的 Iceberg 表,这些表是通过使用 COPY INTO 表命令从兼容 Iceberg 的 Parquet 数据文件中加载数据生成的。

    • 支持读取 Iceberg v2 表。

    • 以下功能支持读取 Iceberg V3 表(公共预览版):

      • 变体数据类型

      • 行沿袭

      不支持所有其他 Iceberg V3 功能,包括默认值和地理数据类型。

  • 访问控制:

  • 克隆和转换的表:

    • 分发的凭据不支持读取克隆或转换的表。要读取这些表,请使用对象存储的直接访问权限。

使用外部查询引擎写入 Iceberg 表时,请注意以下事项:

  • 表操作:

    • 您不能使用 CREATE TABLE 语句指定基本位置。

      当您创建 Snowflake 托管的表而不指定基本位置时,Snowflake 会为该表构建以下路径:STORAGE_BASE_URL/database/schema/table_name.randomId/[data | metadata]/

    • 不支持外部引擎中的 CREATE TABLE AS SELECT (CTAS)。

    • 不支持等值删除。

    • 您不能使用行级删除来写入表,仅支持写入时复制模式。

    • 不支持创建 Iceberg 标签和分支。

    • 仅 Iceberg 版本 2 支持外部引擎写入,目前不支持写入 Iceberg 版本 3 (v3) 表(公共预览版)。

    • 不支持写入使用 KMS 加密的外部卷。

    • 不支持写入 Snowflake 中的动态表。

    • 不支持写入共享的 Iceberg 表。

    • 不支持注册 Iceberg 表。

  • 维护操作

    • 您无法将表回滚到以前的快照。

    • 不支持快照过期操作。

    • 您无法将 Iceberg 表从 v2 升级到 v3。

  • 克隆和转换的表:

    • 分发的凭据不支持写入克隆或转换的表。要写入这些表,请将外部查询引擎直接连接到存储表的对象存储。

    • 您无法写入从外部托管转换为 Snowflake 托管的 Iceberg 表。

  • Streams:

    • 在 Iceberg V2 表上,写入时复制操作会导致标准流将更新或重新定位的行表示为 DELETE 记录,后跟同一行的 INSERT 记录。

  • 细粒度访问控制策略:

    • 不支持写入具有细粒度访问控制策略或标签的表。