通过 Snowflake Horizon 目录使用外部引擎查询 Apache Iceberg™ 表¶
This preview introduces support for querying Snowflake-managed Apache Iceberg™ tables by using an external query engine through Snowflake Horizon Catalog. To ensure this interoperability with external engines, Apache Polaris™ (incubating) (https://github.com/apache/polaris) is integrated into Horizon Catalog. In addition, Horizon Catalog exposes Apache Iceberg™ REST APIs. These APIs let you read the tables by using external query engines.
要使用外部查询引擎查询 Snowflake 托管的 Iceberg 表,您可以使用此功能,而不是 将 Sguowflake 托管的 Iceberg 表与 Snowflake Open Catalog 同步。有关 Open Catalog 的更多信息,请参阅 Snowflake Open Catalog 概述。
通过 Horizon 目录将外部查询引擎连接到 Iceberg 表,您可以执行以下任务:
使用任何支持开放 Iceberg REST 协议的外部查询引擎(例如 Apache Spark™)查询这些表。
使用单个 Horizon 目录端点,查询新的或现有的 Snowflake 账户中任何现有和新的 Snowflake 托管的 Iceberg 表。
使用 Snowflake 中的现有用户、角色、策略和身份验证来查询表。
使用分发的凭据。
有关 Snowflake Horizon 目录的更多信息,请参阅 Snowflake Horizon 目录。
下图显示了外部查询引擎通过 Horizon 目录读取 Snowflake 托管的 Iceberg 表,以及 Snowflake 对这些表的读取和写入:
计费¶
Horizon Iceberg REST 目录 API 适用于所有 Snowflake 版本。
API 请求按每百万次调用 0.5 Credit 计费,并作为云服务进行收费。
对于跨区域数据访问,将适用 Snowflake 服务消耗表 中的标准跨区域数据出口费。
备注
在此功能正式发布之前,客户不会收到任何账单。
准备工作¶
检索包含要查询的 Iceberg 表的 Snowflake 的账户账户标识符。有关说明,请参阅 账户标识符。您可以在 将外部查询引擎连接到 Iceberg 表 时指定此标识符。
小技巧
要获取您的账户标识符,请使用 SQL,您可以运行以下命令:
SELECT CURRENT_ORGANIZATION_NAME() || '-' || CURRENT_ACCOUNT_NAME();
专用连接(可选)¶
为确保安全连接,建议在访问 Horizon Catalog 端点时,为您的 Snowflake 账户配置 入站 和 出站 专用连接。
备注
专用连接仅支持存储在 Amazon S3 或 Azure 存储 (ADLS) 中的由 Snowflake 管理的 Iceberg 表。
使用外部查询引擎查询 Iceberg 表的工作流程¶
要使用外部查询引擎查询 Iceberg 表,请完成以下步骤:
创建 Iceberg 表。
配置访问控制。
获取用于身份验证的访问令牌。
Verify access token permissions.
(可选)配置数据保护策略。
通过 Horizon 目录将外部查询引擎连接到 Iceberg 表。
查询 Iceberg 表。
第 1 步:创建 Iceberg 表¶
重要
如果您已经拥有要查询的 Snowflake 托管的 Iceberg 表,则可以跳过此步骤。
在此步骤中,您将创建 Snowflake 托管的 Iceberg 表,这些表使用 Snowflake 作为目录,从而支持通过外部查询引擎对这些表进行查询。有关说明,请参阅以下主题:
教程:创建第一个 Apache Iceberg™ 表:选择使用 时默认使用的角色和仓库。本教程展示了如何创建数据库、创建 Snowflake 托管的 Iceberg 表以及将数据加载到表中。
创建 Snowflake 托管的 Iceberg 表:Snowflake 托管的 Iceberg 表的创建示例代码。
第 2 步:配置访问控制¶
重要
通过 Horizon 目录端点访问 Iceberg 表时,不支持角色名称中包含连字符 (-) 的 Snowflake 角色。
如果您已经配置具备访问目标 Iceberg 表权限的角色,则可以跳过此步骤。
在此步骤中,您将为要使用外部查询引擎查询的 Snowflake 托管的 Iceberg 表配置访问控制。例如,您可以在 Snowflake 中设置以下角色:
DATA_ENGINEER 角色,该角色有权访问数据库中的所有架构和所有 Snowflake 托管的 Iceberg 表。
DATA_ANALYST 角色,该角色可以访问数据库中的一个架构,但只能访问该架构内的两个 Snowflake 托管的 Iceberg 表。
第 3 步:获取用于身份验证的访问令牌¶
在此步骤中,您将获得一个访问令牌,您必须使用该令牌对 Snowflake 账户的 Horizon 目录端点进行身份验证。您需要为配置为可以访问 Snowflake 托管的 Iceberg 表的每个用户(服务或人员)和角色获取访问令牌。例如,您需要为具有 DATA_ENGINEER 角色的用户获取一个访问令牌,并为具有另一个 DATA_ANALYST 角色的用户再获取一个访问令牌。
You specify this access token later when you connect an external query engine to Iceberg tables through Horizon Catalog.
您可以使用以下身份验证选项之一获取访问令牌:
External OAuth¶
If you're using External OAuth, generate an access token for your identity provider. For instructions, see External OAuth 概览.
备注
对于外部 OAuth,您还可以使用自动令牌刷新配置与引擎的连接,而不是指定访问令牌。
密钥对身份验证¶
If you use key-pair authentication, to obtain an access token, you sign a JSON web token (JWT) with your private key.
The following steps cover how to generate an access token for key-pair authentication:
第 1 步:配置密钥对身份验证¶
在此步骤中,您需要执行以下任务:
生成私钥
生成公钥
安全地存储私钥和公钥
授予向 Snowflake 用户分配公钥的权限
将公钥分配给 Snowflake 用户
验证用户的公钥指纹
有关说明,请参阅 配置密钥对身份验证。
第 2 步:向用户授予角色¶
运行 GRANT ROLE 命令,将具有查询目标表权限的 Snowflake 角色授予密钥对身份验证用户。例如,要向 my_service_user 用户授予 ENGINEER 角色,请运行以下命令:
GRANT ROLE ENGINEER to user my_service_user;
第 3 步:生成 JSON Web 令牌 (JWT)¶
在此步骤中,您将使用 SnowSQL 生成用于密钥对身份验证的 JSON Web 令牌 (JWT)。
备注
您必须在计算机上安装 SnowSQL。
或者,您也可以使用 Python、Snowflake CLI、Java 或 Node.js 生成 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>is the account identifier for your Snowflake account, in the format<organization_name>-<account_name>. To find the account identifier, see 准备工作. An example of an account identifier ismyorg-myaccount.<account_locator>是 Snowflake 账户的账户定位器。要查找您的账户定位器,请参阅 在 Snowsight 中查找您的 Snowflake 账户信息,并并在 Account Details 对话框中查看 账户定位器。
<user_name>是 Snowflake 用户的用户名,且该用户已获分配公钥。
Step 4: Generate an access token¶
重要
要生成访问令牌,您必须先 生成一个 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>is the account identifier for your Snowflake account, in the format<organization_name>-<account_name>. To find the account identifier, see 准备工作. An example of an account identifier ismyorg-myaccount.<role>is the Snowflake role that is granted access to Iceberg tables, such as ENGINEER.<JWT_token>是您在上一步中生成的 JWT。
Programmatic access token (PAT)¶
If you use PATs, generate a PAT for authentication.
First, you generate a PAT, which you use to connect an external query engine to Iceberg tables. Then, you generate an access token, which you only use to verify the permissions for your PAT.
第 1 步:生成 PAT¶
有关如何配置和生成 PAT,请参阅 用于身份验证的编程访问令牌。
Step 2: Generate an access token for your 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>is the account identifier for your Snowflake account, in the format<organization_name>-<account_name>. To find the account identifier, see 准备工作. An example of an account identifier ismyorg-myaccount.<role>is the Snowflake role that is granted to your PAT and has access to the Iceberg tables you want to query, such as ENGINEER.<PAT_token>是您在上一步骤生成的 PAT 值。
Step 4: Verify access token permissions¶
在此步骤中,您将验证在上一步中获取的访问令牌的权限。
验证对 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>is the account identifier for your Snowflake account, in the format<organization_name>-<account_name>. To find the account identifier, see 准备工作. An example of an account identifier ismyorg-myaccount.<access_token>is your access token that you generated. If you're using a PAT, this value is the access token you generated, not the personal access token (PAT) you generated.<database_name>是要查询的数据库的名称。重要
您必须以 全部大写字母 指定数据库名称,即使它是使用小写字母创建的。
返回值示例:
{
"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>is the account identifier for your Snowflake account, in the format<organization_name>-<account_name>. To find the account identifier, see 准备工作. An example of an account identifier ismyorg-myaccount.<database_name>是要检索其元数据的表的数据库。<namespace_name>是要检索其元数据的表的命名空间。<table_name>是要检索其元数据的表。<access_token>is your access token that you generated. If you're using a PAT, this value is the access token you generated, not the personal access token (PAT) you generated.
重要
您必须使用 全部大写字母 指定数据库、命名空间和表名称,即使对象是使用小写字母创建的。
(可选)第 5 步:配置数据保护策略¶
在此步骤中,为 Iceberg 表配置数据保护策略。如果没有需要使用 Snowflake 数据策略保护的表,可以继续执行下一步。
备注
受数据保护策略保护的表可通过 Horizon Iceberg RESTAPI 或使用 Apache Spark™ 访问。
有关配置数据保护策略的说明,请参阅 在通过 Horizon Iceberg REST API 访问的 Iceberg 表上配置数据保护策略并使用 Apache Spark™。
Step 6: Connect an external query engine to Iceberg tables through Horizon Catalog¶
In this step, you connect an external query engine to Iceberg tables through Horizon Catalog. With this connection, you can query the tables by using the external query engine.
外部引擎使用 Snowflake 公开的 Apache Iceberg™ REST 端点。对于您的 Snowflake 账户,此端点采用以下格式:
https://<account_identifier>.snowflakecomputing.cn/polaris/api/catalog
The example code in this step shows how to set up a connection in Spark, and the example code is in PySpark. For more information, see the following sections:
使用外部 OAuth 或密钥对身份验证进行连接¶
使用以下配置之一进行连接:
To access Iceberg tables that don't have Snowflake data protection policies configured, connect an external query engine without enforcing data policies.
To access Iceberg tables that have Snowflake row access and masking policies configured, connect an external query engine with data policies enforced.
Connect an external query engine without enforcing data policies¶
To connect the external query engine to Iceberg tables by using External OAuth or key pair authentication. Use the following example code.
此代码不强制执行数据保护策略:
# 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>is your Snowflake account identifier for the Snowflake account that contains the Iceberg tables that you want to query. To find this identifier, see 准备工作.<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) 中,请执行以下步骤:
注释以下行:
f"org.apache.iceberg:iceberg-aws-bundle:{ICEBERG_VERSION}"取消注释以下行:
# f"org.apache.iceberg:iceberg-azure-bundle:{ICEBERG_VERSION}"
Connect an external query engine with data policies enforced¶
要连接已强制执行的数据保护策略,请参阅 将 Spark 连接到 Iceberg 表。
使用编程访问令牌 (PAT) 进行连接¶
使用以下配置之一进行连接:
If you don't use data protection policies with the Iceberg tables that you want to query, use the configuration Connect an external query engine without enforcing data policies.
If you use data protection policies with the Iceberg tables that you want to query, use the configuration Connect an external query engine with data policies enforced.
Connect an external query engine without enforcing data policies¶
To connect the external query engine to Iceberg tables by using a programmatic access token (PAT), use the following example code.
此代码不强制执行数据保护策略:
# 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>is your Snowflake account identifier for the Snowflake account that contains the Iceberg tables that you want to query. To find this identifier, see 准备工作.<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) 中,请执行以下步骤:
注释以下行:
f"org.apache.iceberg:iceberg-aws-bundle:{ICEBERG_VERSION}"取消注释以下行:
# f"org.apache.iceberg:iceberg-azure-bundle:{ICEBERG_VERSION}"
Connect an external query engine with data policies enforced¶
要连接已强制执行的数据保护策略,请参阅 将 Spark 连接到 Iceberg 表。
Step 7: Query Iceberg tables¶
此步骤提供了使用 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 表的注意事项¶
使用外部查询引擎查询 Iceberg 表时,请考虑以下事项:
对于 Snowflake 中的表:
仅支持 Snowflake 托管的 Iceberg 表。
不支持查询远程或外部托管的 Iceberg 表,包括 Delta Direct 和 Parquet Direct 表以及 Snowflake 原生表。
您可以查询,但不能写入 Iceberg 表。
仅 Iceberg 版本 2 或更早版本支持外部读取。
This feature is only supported for Snowflake-managed Iceberg tables that are stored on Amazon S3, Google Cloud, or Microsoft Azure for all public cloud regions. S3-compatible non-AWS storage is not yet supported.
受以下细粒度数据策略保护的表,可以通过 Horizon Iceberg REST API 访问,并使用 Apache Spark™:
Masking policies
基于标签的掩码策略
行访问策略
通过 Horizon 目录端点访问 Iceberg 表时,不支持角色名称中包含连字符 (-) 的 Snowflake 角色。
不支持显式授予 Horizon 目录端点对存储账户的访问权限。我们建议使用专用连接,以确保从外部引擎到 Horizon 目录,以及从 Horizon 目录到存储账户的连接安全。