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

此预览版引入了通过 Snowflake Horizon 目录使用外部查询引擎查询 Snowflake 托管的 Apache Iceberg™ 表的支持。为了确保与外部引擎的互操作性,`_Apache Polaris™(孵化中)`<https://github.com/apache/polaris (https://github.com/apache/polaris)> 已集成到 Horizon 目录中。此外,Horizon 目录还公开了 Apache Iceberg™ REST APIs,它允许您使用外部查询引擎读取表。

要使用外部查询引擎查询 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 目录读取 Snowflake 托管的 Iceberg 表,以及 Snowflake 读取和 写入这些表。

计费

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

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

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

备注

在此功能正式发布之前,客户不会收到任何账单。

准备工作

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

小技巧

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

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

专用连接(可选)

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

备注

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

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

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

  1. 创建 Iceberg 表。

  2. 配置访问控制。

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

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

  5. 查询 Iceberg 表。

第 1 步:创建 Iceberg 表

重要

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

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

第 2 步:配置访问控制

重要

  • 通过 Horizon 目录端点访问 Iceberg 表时,不支持角色名称中包含连字符 (-) 的 Snowflake 角色。

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

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

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

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

有关说明,请参阅 配置访问控制。有关 Snowflake 中访问控制的详细信息,请参阅 访问控制概述

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

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

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

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

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

    备注

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

  • 密钥对身份验证:如果您使用密钥对身份验证,且要获取访问令牌,您需要使用私钥签署 JSON 网络令牌 (JWT)。有关说明,请参阅 密钥对身份验证

  • 编程访问令牌 (PAT):如果您使用 PATs,则生成用于身份验证的 PAT。有关说明,请参阅 用于身份验证的编程访问令牌

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

在此步骤中,您将通过 Horizon 目录将外部查询引擎连接到 Iceberg 表。此连接允许您使用外部查询引擎对表进行查询。

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

https://<accountidentifier>.snowflakecomputing.cn/polaris/api/catalog
Copy

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

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

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

# Snowflake Horizon Catalog Configuration, change as per your environment

CATALOG_URI = "https://<accountidentifier>.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
Copy

其中:

  • <accountidentifier> 是包含要查询的 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://<accountidentifier>.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
Copy

其中:

  • <accountidentifier> 是包含要查询的 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}"

第 5 步:查询 Iceberg 表

此步骤提供了使用 Apache Spark™ 查询 Iceberg 表的以下代码示例:

  • 显示命名空间

  • 使用命名空间

  • 显示表

  • 查询表

显示命名空间

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

使用命名空间

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

显示表

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

查询表

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

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

使用外部查询引擎查询 Iceberg 表时,请考虑以下事项:

  • 对于 Snowflake 中的表:

    • 仅支持 Snowflake 托管的 Iceberg 表。

    • 不支持查询远程或外部托管的 Iceberg 表,包括 Delta Direct 和 Parquet Direct 表以及 Snowflake 原生表。

  • 您可以查询,但不能写入 Iceberg 表。

  • 仅 Iceberg 版本 2 或更早版本支持外部读取。

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

  • 如果在表上定义了以下细粒度访问控制 (FGAC) 策略,则无法通过 Horizon Iceberg REST API 查询该 Iceberg 表:

    • 行访问策略

    • 列级安全性

  • 通过 Horizon 目录端点访问 Iceberg 表时,不支持角色名称中包含连字符 (-) 的 Snowflake 角色。

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

语言: 中文