Iceberg 読み取りを有効化した Delta テーブルの Snowflake からの参照とカタログフェデレーションによる Snowflake 管理の Iceberg テーブルの Databricks からの参照を試してみた

Iceberg 読み取りを有効化した Delta テーブルの Snowflake からの参照とカタログフェデレーションによる Snowflake 管理の Iceberg テーブルの Databricks からの参照を試してみた

2025.12.14

はじめに

Databricks では Delta Lake に格納されたテーブルに対する Iceberg 読み取りを有効にする機能が提供されています。

https://docs.databricks.com/aws/ja/delta/uniform

この機能を使用すると、Delta テーブルに対して Iceberg メタデータを生成し Iceberg クライアントから参照できるようになります。

Snowflake では Apache Iceberg REST カタログ統合というオブジェクトを使用することで、Apache Iceberg REST API 仕様 に準拠した Apache Iceberg テーブル で管理されているリモートカタログにアクセスできるように構成できます。この機能により Iceberg 読み取りを有効化した Delta Lake テーブルを参照できます(参照のみ)。

また、Databricks 側ではカタログフェデレーションという機能が提供されており、この機能を使用することで、Snowflake 管理の Iceberg テーブルに対して Databricks 側のコンピュートリソースを使用し、直接オブジェクトストレージ内の外部テーブルにアクセスできます。

https://docs.databricks.com/aws/ja/query-federation/catalog-federation

それぞれを試した内容を本記事でまとめてみます。

なお、上記の内容は公式からもデモとして公開されていましたので、こちらの内容を参考にしています。

https://www.youtube.com/watch?v=HbY80QjVtKg

前提条件

以下の環境を使用しています。

  • Databricks:Free Edition
  • Snowflake:トライアルアカウント

Iceberg 読み取りを有効化し Snowflake から参照

以下の作業を行うことで、Delta テーブルを Snowflake から参照します。

  • Databricks 側
    • S3 を使用する外部ロケーションを作成
    • Iceberg 読み取りを有効にする Delta テーブルを作成
    • OAuth シークレットを作成
  • Snowflake 側
    • カタログ統合を作成
    • 外部ボリュームを作成
    • カタログリンクデータベースを作成

Databricks 側:S3 を使用する外部ロケーションの作成

はじめに、Databricks 側で外部ロケーションオブジェクトを作成し S3 バケットに接続します。

https://docs.databricks.com/aws/en/connect/unity-catalog/cloud-storage/s3/s3-external-location-manual

AWS 側で任意の名称で IAMロールを作成後、「Catalog」メニューから「Create Credential」を選択します。

image

次の画面で「Storage Credential」を選択し Credential Type は AWS IAM Role を選択し Arn に先の手順で作成した IAM ロールの Arn を指定します。

image 1

「Create」をクリックすると、信頼ポリシーが表示されるので、IAM ロール側の信頼ポリシーを変更します。

image 2

続けて、「Catalog」メニューから「Create an external location」を選択します。

image 3

ここでは「Manual」より作成しました。

image 4

次の画面で対象とする S3 バケットの URL と認証方法として、先の手順で作成済みの Credential を指定します。

image 5

作成後は、テスト接続も行えます。

image 6

上記の手順については、以下の記事も参考になります。

https://dev.classmethod.jp/articles/databricks-unity-catalog-s3/

Databricks 側:Iceberg 読み取りを有効にする Delta テーブルを作成

SQL エディタで以下のクエリを実行し、Iceberg 読み取りを有効にする Delta テーブルを作成します。

CREATE CATALOG IF NOT EXISTS mycatalog;
CREATE SCHEMA IF NOT EXISTS mycatalog.iceberg_test;

USE CATALOG mycatalog;
USE SCHEMA iceberg_test;

CREATE TABLE mycatalog.iceberg_test.customer_data (
  customer_id INT,
  customer_name STRING,
  email STRING,
  registration_date DATE,
  city STRING
)
USING DELTA
LOCATION 's3://<バケット名>/mycatalog/iceberg_test/customer_data/'
TBLPROPERTIES (
  'delta.columnMapping.mode' = 'name',
  'delta.enableIcebergCompatV2' = 'true',
  'delta.universalFormat.enabledFormats' = 'iceberg'
);

こちらについては、以下に記載があります。

https://docs.databricks.com/aws/ja/delta/uniform#テーブル作成中の-iceberg-読み取りを有効にする

テーブル作成後、レコードを追加しデータを確認します。

INSERT INTO customer_data
(customer_id, customer_name, email, registration_date, city)
VALUES
  (1, 'Taro Yamada', 'taro.yamada@example.com', DATE '2025-12-01', 'Tokyo'),
  (2, 'Hanako Suzuki', 'hanako.suzuki@example.com', DATE '2025-12-02', 'Osaka'),
  (3, 'John Smith', 'john.smith@example.com', DATE '2025-12-03', 'Seattle');

SELECT * FROM customer_data ORDER BY customer_id;

image 7

この状態で S3 側を確認すると、指定のパスに各種ファイルが作成されています。

image 8

Databricks 側:OAuthシークレット を作成

Snowflake からアクセスするために、以下の手順に沿ってサービスプリンシパルを作成し、権限を付与します。

https://docs.databricks.com/aws/ja/admin/users-groups/manage-service-principals

https://docs.databricks.com/gcp/ja/dev-tools/auth/oauth-m2m

Workspace の設定より「Identity and access 」メニューを開き Service principals 内の「Manage」をクリックします。

image 9

下図の画面となるので「Add service principal」をクリックします。

image 10

次の画面では「Add New」をクリックし、任意の名称でサービスプリンシパルを作成します。

image 11

サービスプリンシパルを作成したら、対象のサービスプリンシパルをクリックし「Secrets」タブより新しいトークンを生成します。

image 12

期限を設定しトークンを生成します。

image 13

シークレットとクライアントIDが表示されるので、控えておきます。

image 14

また、トークンの「Configuration」タブからアプリケーションIDを確認できます。権限付与時に使用するため、こちらも控えておきます。

続けて、サービスプリンシパルに参照権限を付与します。

GRANT USE CATALOG ON CATALOG mycatalog TO `<アプリケーションID>`;
GRANT USE SCHEMA  ON SCHEMA mycatalog.iceberg_test TO `<アプリケーションID>`;
GRANT SELECT ON TABLE mycatalog.iceberg_test.customer_data TO `<アプリケーションID>`;

Databricks 側の準備は以上です。

Snowflake 側:カタログ統合を作成

Snowflake 側からは、Iceberg REST カタログ統合を使用します。

https://docs.snowflake.com/ja/sql-reference/sql/create-catalog-integration-rest

以下のコマンドでカタログ統合を作成します。

-- 変数を定義
set client_id = 'クライアントID';
set client_secret = 'クライアントシークレット';
set workspace_url='https://xxxxx.cloud.databricks.com';
set catalog_uri = $workspace_url||'/api/2.1/unity-catalog/iceberg';
set token_uri = $workspace_url||'/oidc/v1/token';
set catalog_name = 'mycatalog';
set catalog_namespace = 'iceberg_test';

--Iceberg REST カタログ統合を作成
CREATE OR REPLACE CATALOG INTEGRATION dbx_catalog_int
  CATALOG_SOURCE = ICEBERG_REST
  TABLE_FORMAT = ICEBERG
  CATALOG_NAMESPACE = $catalog_namespace
  REST_CONFIG = (
    CATALOG_URI = $catalog_uri
    CATALOG_NAME = $catalog_name
    CATALOG_API_TYPE = PUBLIC
 )
  REST_AUTHENTICATION = (
    TYPE = OAUTH
    OAUTH_TOKEN_URI = $token_uri
    OAUTH_CLIENT_ID = $client_id
    OAUTH_CLIENT_SECRET = $client_secret
    OAUTH_ALLOWED_SCOPES = ('all-apis', 'sql')
  )
  ENABLED = TRUE
  REFRESH_INTERVAL_SECONDS = 30;

カタログ統合を作成したら、以下でステータスを確認できます。

>SELECT SYSTEM$VERIFY_CATALOG_INTEGRATION('dbx_catalog_int');
+------------------------------------------------------+
| SYSTEM$VERIFY_CATALOG_INTEGRATION('DBX_CATALOG_INT') |
|------------------------------------------------------|
| {                                                    |
|   "success" : true,                                  |
|   "errorCode" : "",                                  |
|   "errorMessage" : ""                                |
| }                                                    |
+------------------------------------------------------+

当初、サービスプリンシパルに権限を付与しておらず、この場合下図のエラーとなりました。

{
  ""success"" : false,
  ""errorCode"" : ""004139"",
  ""errorMessage"" : ""SQL Execution Error: Resource on the REST endpoint of catalog integration UNITY_UPATELCATALOG_INT_OAUTH is forbidden due to error: Forbidden: Not authorized to make this request.""
}

Snowflake 側:外部ボリュームを作成

S3 にアクセスするための外部ボリュームを作成します。

CREATE OR REPLACE EXTERNAL VOLUME s3_dbx_ext_vol
  STORAGE_LOCATIONS =
    (
      (
        NAME = 's3_dbx_ext_vol'
        STORAGE_PROVIDER = 'S3'
        STORAGE_BASE_URL = 's3://<バケット名>/'
        STORAGE_AWS_ROLE_ARN = 'arn:aws:iam::xxxxxxxxxxxx:role/iceberg-role'
        ENCRYPTION=(TYPE='AWS_SSE_S3')
      )
    )
  ALLOW_WRITES = TRUE;

外部ボリューム作成後は、以下のコマンドを実行し Snowflake アカウントの IAM ユーザーと外部 ID を取得し、IAM ロールの信頼関係を更新します。

DESC EXTERNAL VOLUME s3_dbx_ext_vol;

AWS での作業後、以下を実行しsuccessプロパティがtrue となっていれば問題ないです。

SELECT SYSTEM$VERIFY_EXTERNAL_VOLUME('s3_dbx_ext_vol');

Snowflake 側:カタログリンクデータベースを作成

作成したカタログ統合と外部ボリュームを使用し、カタログリンクデータベースを作成します。

CREATE DATABASE dbx_test_db
  LINKED_CATALOG = (
    CATALOG = 'dbx_catalog_int',
    SYNC_INTERVAL_SECONDS = 30
  )
  EXTERNAL_VOLUME = 's3_dbx_ext_vol';

ステータスは以下で確認できます。

SELECT SYSTEM$CATALOG_LINK_STATUS( 'dbx_test_db' );

データベース作成後、UI からは下図のようにデータベーススキーマやテーブルを確認できました。

image 15

Databricks 側で作成されたテーブルが同期されており、通常のテーブルのように Snowflake 側からクエリできます。

>SELECT * FROM dbx_test_db."iceberg_test"."customer_data";
+-------------+---------------+---------------------------+-------------------+---------+
| customer_id | customer_name | email                     | registration_date | city    |
|-------------+---------------+---------------------------+-------------------+---------|
|           1 | Taro Yamada   | taro.yamada@example.com   | 2025-12-01        | Tokyo   |
|           2 | Hanako Suzuki | hanako.suzuki@example.com | 2025-12-02        | Osaka   |
|           3 | John Smith    | john.smith@example.com    | 2025-12-03        | Seattle |
+-------------+---------------+---------------------------+-------------------+---------+

Databricks 側:テーブルにレコードを追加

Databricks側でレコードを追加してみます。

-- Databricks 側でレコードを追加
INSERT INTO customer_data
(customer_id, customer_name, email, registration_date, city)
VALUES
  (4, 'Sakura Tanaka', 'sakura.tanaka@example.com', DATE '2025-12-04', 'Nagoya'),
  (5, 'Kenji Ito', 'kenji.ito@example.com', DATE '2025-12-05', 'Fukuoka'),
  (6, 'Emily Chen', 'emily.chen@example.com', DATE '2025-12-06', 'San Francisco'),
  (7, 'Akira Sato', 'akira.sato@example.com', DATE '2025-12-07', 'Sapporo'),
  (8, 'Maria Garcia', 'maria.garcia@example.com', DATE '2025-12-08', 'New York');

Snowflake 側で同期完了後に確認すると、レコードが追加されていることを確認できました。

>SELECT * FROM dbx_test_db."iceberg_test"."customer_data";
+-------------+---------------+---------------------------+-------------------+---------------+
| customer_id | customer_name | email                     | registration_date | city          |
|-------------+---------------+---------------------------+-------------------+---------------|
|           4 | Sakura Tanaka | sakura.tanaka@example.com | 2025-12-04        | Nagoya        |
|           5 | Kenji Ito     | kenji.ito@example.com     | 2025-12-05        | Fukuoka       |
|           6 | Emily Chen    | emily.chen@example.com    | 2025-12-06        | San Francisco |
|           7 | Akira Sato    | akira.sato@example.com    | 2025-12-07        | Sapporo       |
|           8 | Maria Garcia  | maria.garcia@example.com  | 2025-12-08        | New York      |
|           1 | Taro Yamada   | taro.yamada@example.com   | 2025-12-01        | Tokyo         |
|           2 | Hanako Suzuki | hanako.suzuki@example.com | 2025-12-02        | Osaka         |
|           3 | John Smith    | john.smith@example.com    | 2025-12-03        | Seattle       |
+-------------+---------------+---------------------------+-------------------+---------------+

カタログフェデレーションで Snowflake 管理の Iceberg テーブルを Databricks から参照する

先は Snowflake から Databricks のテーブルを参照しました。

次は Snowflakeで作成した Iceberg テーブルを Databricks 側から Databricks のエンジンで直接ストレージ経由で参照します。

https://docs.databricks.com/aws/en/query-federation/catalog-federation

https://docs.databricks.com/aws/en/query-federation/snowflake-catalog-federation

Snowflake 側:Databricks からクエリするデータベースとテーブルを作成

事前に Snowflake 側で以下を実行し、Databricks からの参照先となるデータベースと、その中に通常のテーブルと Snowflake 管理の Iceberg テーブルを作成しました。外部ボリュームは先の手順と同じものを使用しています。

-- データベース
CREATE DATABASE sf_test_db;

-- 通常のSnowflakeテーブル
CREATE OR REPLACE TABLE SF_TEST_DB.PUBLIC.SNOW_CUSTOMERS_BASIC (
  CUSTOMER_ID        NUMBER(38,0),
  CUSTOMER_NAME      STRING,
  EMAIL              STRING,
  REGISTRATION_DATE  DATE,
  CITY               STRING
);

INSERT INTO SF_TEST_DB.PUBLIC.SNOW_CUSTOMERS_BASIC
(CUSTOMER_ID, CUSTOMER_NAME, EMAIL, REGISTRATION_DATE, CITY)
VALUES
  (1, 'Taro Yamada',   'taro.yamada@example.com',   '2025-12-01', 'Tokyo'),
  (2, 'Hanako Suzuki', 'hanako.suzuki@example.com', '2025-12-02', 'Osaka'),
  (3, 'John Smith',    'john.smith@example.com',    '2025-12-03', 'Seattle'),
  (4, 'Sakura Tanaka', 'sakura.tanaka@example.com', '2025-12-04', 'Nagoya'),
  (5, 'David Kim',     'david.kim@example.com',     '2025-12-05', 'Los Angeles');

-- Snowflake管理のIcebergテーブル
CREATE ICEBERG TABLE snow_customers_iceberg
    EXTERNAL_VOLUME = 's3_dbx_ext_vol'
    CATALOG = 'SNOWFLAKE'
    BASE_LOCATION = 'snow-test/'
    AS SELECT * FROM SF_TEST_DB.PUBLIC.SNOW_CUSTOMERS_BASIC;

Iceberg テーブル作成後に S3 側を確認すると、データとメタデータファイルを確認できます。

image 16

Databricks 側:コネクションを作成

Databricks 側の Snowflake との接続構成手順は以下に記載があります。

https://docs.databricks.com/aws/en/query-federation/snowflake-catalog-federation

オブジェクトストレージを参照するために、事前に Databricks 側の外部ロケーションを構成する必要がありますが、ここでは先の手順で使用したものと同じバケットに Snowflake 管理のIcebergテーブルも作成しているため、新たに構成は行いません。(同じ外部ロケーションを使用します)

次の手順として、コネクションを作成します。Workspace の「Create a connection」をクリックし、任意のコネクション名と認証方式を指定します。

※ここでは簡単にベーシック認証を使用している点にご注意ください。

image 17

ホスト名や認証資格情報を入力します。

image 18

Snowflake 側のコンピュートリソースやロールなどを指定します。

image 19

Databricks におけるカタログ名と対応する Snowflake データベースを指定します。あわせて「Authorized paths」や「Storage location」を指定します。ここでは、すでに作成済みの外部ロケーションを指定しています。

image 20

構成後、接続をテストできます。

image 21

その他はデフォルトとして、コネクションとカタログフェデレーションの構成を完了します。

Databricks からクエリ

カタログフェデレーションの構成後、Databricks 側から指定のカタログ(Snowflakeにおけるデータベース)内に、Snowflake 上で作成したテーブルを確認できます。Snowflake 管理の Iceberg テーブルとして作成したテーブル(snow_customers_iceberg)は、Iceberg テーブルとして認識されていました。

image 22

Databricks 側から Snowflake 管理の Iceberg テーブルをクエリします。

-- Snowflake管理のIcebergテーブルをクエリ
SELECT * FROM snow_connection_catalog.public.snow_customers_iceberg;

image 23

中身を表示できました。

Snowflake側でレコードを追加してみます。

-- Snowflake管理のIcebergテーブルにレコードを追加
INSERT INTO snow_customers_iceberg
(CUSTOMER_ID, CUSTOMER_NAME, EMAIL, REGISTRATION_DATE, CITY)
VALUES
  (6, 'Yuki Nakamura', 'yuki.nakamura@example.com', '2025-12-06', 'Kyoto'),
  (7, 'Emily Chen',    'emily.chen@example.com',    '2025-12-07', 'San Francisco'),
  (8, 'Maria Garcia',  'maria.garcia@example.com',  '2025-12-08', 'New York');

Databricks 側で同じテーブルをクエリするとレコードの追加が反映された状態で表示されます。

image 24

クエリ履歴

通常の Snowflake テーブルをクエリすると、下図のようなクエリが記録されていました。

image 25

Databricks 側の上記クエリ

-- 通常のSnowflakeテーブルをクエリ
SELECT * FROM snow_connection_catalog.public.snow_customers_basic;

一方で Snowflake 管理の Iceberg テーブルクエリ時は上記のような実際にテーブルを参照するクエリは履歴に追加されていなかったため、S3 に対して直接 Databricks 側のリソースでクエリを実行していると考えられました。

さいごに

Delta Lake に格納されたテーブルに対する Iceberg 読み取りを有効化し Snowflake からの参照とカタログフェデレーションによる Snowflake 管理の Iceberg テーブルへの参照を試してみました。

Iceberg 読み取りの有効化の場合、Snowflake などからは読み取り専用です。

https://docs.databricks.com/aws/en/external-access/iceberg#requirements

Managed Iceberg の場合、書き込みもサポートされているとのことなので、試してみたいと思います。

https://www.databricks.com/jp/blog/whats-new-databricks-unity-catalog-data-ai-summit-2025

https://www.databricks.com/jp/blog/announcing-full-apache-iceberg-support-databricks

本記事の内容が何かの参考になれば幸いです。

参考

https://medium.com/@umeshpatel_us/breaking-silos-integrating-snowflake-and-databricks-unity-catalog-4f30a1468f29

この記事をシェアする

FacebookHatena blogX

関連記事