OneLake の Iceberg ショートカットにより Power BI や Fabric 分析エンジンへの Snowflakeデータの連携を革新する 

## はじめに

Snowflake Iceberg テーブルの作成を OneLake に対して行い、更に OneLake が Iceberg テーブルを自動的に読み替えてくれる機能がプレビュー開始しましたので、これを紹介します。

## Snowflake のデータを Power BI で使いたい！

という声をよくお聞きします。実際に使われている方も多い構成です。

これを実現するための主な構成案として以下のパターンがありますが、　Fabric が登場したことで少し幅ができました。

1. Power BI のみで構成
    1. Power BI のソースにする(Import / Direct Query)
        - Snowflake の IP 制限がない状態場合では簡単だが、Public IP ホワイトリストなどを使用している場合には、以下のいずれかの構成が必要
            - Power BI のリージョンで使用される Azure 全体の IP 許可
            - [オンプレミスデータゲートウェイ](https://learn.microsoft.com/ja-jp/data-integration/gateway/service-gateway-onprem-indepth) を使用する
1. Fabric （OneLake）を活用した構成
    1. Data Factory などの ETL ツールを使用して OneLake にデータを連携したうえで、Power BI のソースにする(Import / Direct Query / Direct Lake)
        - オンプレミスデータゲートウェイを介したプライベートアクセスはできますが、ETL(ELT)が必要で、ニアリアルタイムに Snowflake データを Power BI に反映することはできません。
    1. [Fabric Mirroring](https://learn.microsoft.com/ja-jp/fabric/database/mirrored-database/snowflake) を使用して OneLake に Snowflake 上のデータをニアリアルタイム同期する
        - ニアリアルタイムかつ V-Order という Fabric の独自エンコーディング技術により、クエリ性能を向上させた状態で OneLake に書き込まれるという点で有力な構成ですが、同期中はStreamが実行されるため仮想 WH が起動することにより Snowflake 側のコスト増に注意が必要です。
        - また、現時点で Snowflake 側で IP 制限などのネットワークセキュリティを十分にかけることはできません。（Azure 全体の IP 許可は可能）

## Snowflake の Iceberg テーブルを通じた 相互運用性の向上

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/8cfd7d67-520b-e9c9-80be-d63e0e9bf3d0.png)


Snowflake の Iceberg テーブルの OneLake ショートカットの発表で、より協力な選択肢が生まれました。
- [Snowflake、Microsoftとのパートナーシップを拡大し、Apache Icebergを通じて相互運用性を向上](https://www.snowflake.com/en/blog/microsoft-partnership-enhancing-interoperability/)
- [Snowflakeとショートカットを使用してOneLakeにIcebergデータを保存し、アクセスします](https://blog.fabric.microsoft.com/en-US/blog/store-and-use-your-snowflake-iceberg-data-in-onelake/)

これにより、Snowflake のデータを **同期処理やデータ移動のために仮想ウェアハウスを立ち上げる必要なく**、**ニアリアルタイムに** 、**IPホワイトリスト設定を緩めることなく**、Power BI を含む Fabric の分析機能で利用することができるようになります。

### Iceberg とは？

[Apache Iceberg](https://iceberg.apache.org/) は、 Databricks が開発し、 OneLake が標準として採用している [Delta Lake](https://delta.io/)にならぶ、レイクハウスフォーマットの一つです。（もう一つ代表的なものは Uber の [Apache Hudi](https://hudi.apache.org/)) 

レイクハウスフォーマットは、データレイク上でテーブルとしての構造化および ACID 特性を実現することで、データウェアハウスサービスのレイヤではなく、ストレージレイヤーに分析ストアを構築します。
これにより、ベンダーロックインのリスクを減らし、異なるプラットフォーム間でデータ活用をシームレスに行うことができるようになります。

参考：
- https://www.slideshare.net/slideshow/a-thorough-comparison-of-delta-lake-iceberg-and-hudi/236682124
- https://www.slideshare.net/slideshow/bigdata-storage-layer-software-nttdata/183323642

## ウォークスルー

構成イメージ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/7407d34a-df77-8d8e-084c-810953a3682f.png)


### 1. レイクハウスの作成

まずはレイクハウスを作成し、Snowflake の外部ボリュームが参照するパスを取得します。

1. [レイクハウスを作成する](https://learn.microsoft.com/ja-jp/fabric/data-engineering/tutorial-build-lakehouse#create-a-lakehouse) を参考に、レイクハウスを作成したら、Iceberg テーブルを作成するディレクトリを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/1db83088-2142-adf6-9b75-8066db558501.png)
2. プロパティから このディレクトリを示す、OneLake の URL を取得します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/e984dc44-edb7-7090-85a2-ed00d369813d.png)
3. 画面右上のユーザーアイコンからテナントIDも取得しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/23613b11-555b-4e23-a2b4-7a5add328143.png)

### 2. 外部ボリュームの作成

Snowflake 側で 外部ボリュームを作成します。
参考：https://docs.snowflake.com/en/user-guide/tables-iceberg-configure-external-volume-azure#step-1-create-an-external-volume-in-snowflake

1. 先ほど取得した OneLake の URL を https -> azure に修正します。
    ```:例
    https://onelake.dfs.fabric.microsoft.com/iceberg_demo/sf_demo.Lakehouse/Files/snowflake_volume
    ↓
    azure://onelake.dfs.fabric.microsoft.com/iceberg_demo/sf_demo.Lakehouse/Files/snowflake_volume
    ```
2. CREATE EXTERNAL COMMAND を実行します。VOLUME名は後で使います。
    ```:sql
    CREATE EXTERNAL VOLUME onelake_sf_demo_ext_volume
      STORAGE_LOCATIONS =
        (
          (
            NAME = 'onelake_sf_demo_location'
            STORAGE_PROVIDER = 'AZURE'
            STORAGE_BASE_URL = 'azure://onelake.dfs.fabric.microsoft.com/iceberg_demo/sf_demo.Lakehouse/Files/snowflake_volume'
            AZURE_TENANT_ID = '<テナントID>'
          )
        );


    ```
3. DESC コマンドで、Snowflake クライアントアプリケーションを使用するための URL と アプリケーションの名前が確認できます。
    ```:sql
    DESC EXTERNAL VOLUME onelake_sf_demo_ext_volume;
    
    ```
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/cc274b22-1383-515b-56d8-d7cf4f673b03.png)
4. URL にアクセスして、Microsoft Graph API のアクセス許可を与えます。（テナントに対する特権が必要です） 
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/a181eb71-ec32-36b1-8d2b-1dbd8781aff8.png)

    :::note info
    
    組織の代理としてのチェックは任意です。後日チェックはつけなくても動作することが確認できました。

    
5. 許可をすると自動実行可能なアクセス許可をもったアプリケーションが Entra ID に登録されます。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/daa74089-8f28-7e0b-52b3-a0c06d153972.png)

### 3. Snowflake クライアントアプリケーションに対してレイクハウスへの書込み権限を付与

作成されたアプリケーションに権限付与を行います。

1. [ワークスペースへのアクセスを許可する](https://learn.microsoft.com/ja-jp/fabric/get-started/give-access-workspaces) を参考に、共同作成者以上のロールを付与します。表示されない場合は、後述の制限事項を参考に、テナント設定などを確認してください。**外部アクセスを許可するテナントスイッチ** なんかは既定で無効なので、対処が必要です。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/ab223ad9-0d7c-37ef-ed8f-28239bf8f362.png)
1. Volume が機能することを確認します。
    ```:sql
    SELECT SYSTEM$VERIFY_EXTERNAL_VOLUME('onelake_sf_demo_ext_volume');
    ```

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/fc2a43e2-4482-c3a8-e08a-119355205b14.png)

:::note info

エンタープライズアプリケーションへのアクセス許可設定の事前準備として、[サービス プリンシパルは Fabric API を使用できます](https://learn.microsoft.com/ja-jp/fabric/admin/service-admin-portal-developer#service-principals-can-use-fabric-apis)を有効化することが必要です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/41600ec1-ded1-4bf2-a7ad-61cce04776ac.png)


:::



### 4. Iceberg テーブルの作成

Snowflake  側で Iceberg テーブルを作成します。

参考：https://docs.snowflake.com/en/user-guide/tutorials/create-your-first-iceberg-table

1. DDL文を発行します。VARCHARなどは STRING に置き換えます
    ```:sql
    
    CREATE OR REPLACE ICEBERG TABLE ICEBIRG_DEMO.PUBLIC.LINEITEM (
    	L_ORDERKEY NUMBER(38,0),
    	L_PARTKEY NUMBER(38,0),
    	L_SUPPKEY NUMBER(38,0),
    	L_LINENUMBER NUMBER(38,0),
    	L_QUANTITY NUMBER(12,2),
    	L_EXTENDEDPRICE NUMBER(12,2),
    	L_DISCOUNT NUMBER(12,2),
    	L_TAX NUMBER(12,2),
    	L_RETURNFLAG STRING,
    	L_LINESTATUS STRING,
    	L_SHIPDATE DATE,
    	L_COMMITDATE DATE,
    	L_RECEIPTDATE DATE,
    	L_SHIPINSTRUCT STRING,
    	L_SHIPMODE STRING,
    	L_COMMENT STRING
    )
      CATALOG = 'SNOWFLAKE'
      EXTERNAL_VOLUME = 'onelake_sf_demo_ext_volume'
      BASE_LOCATION = 'icebirg_demo/public/lineitem';
    ```
1. レイクハウスを確認すると、Iceberg 形式でディレクトリが作成されています
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/4b69460d-21ce-1c45-e26a-496ae16c9051.png)

1. この Iceberg ディレクトリにテーブルショートカットを作成します。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/893723ea-df52-2e59-9118-4544818c06a3.png)
1. [OneLake ショートカットを作成する](https://learn.microsoft.com/ja-jp/fabric/onelake/create-onelake-shortcut)を参考にして、テーブルを示すフォルダをショートカット先にします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/55f3a500-f19c-2867-abce-4db9af07a802.png)

1. データがない状態ではエラー表示されていますが、列情報を parquet から取得しているように感じますので、放置してファイルの内容を見ると delta log が生成されていることがわかります。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/3c8e1ed2-63b2-7ebe-1cda-05223f686528.png)
    iceberg_conversion_log.txt が生成されてました。がこれはエラー。Azure Function が動いているっぽいのが興味深い
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/df3fa85b-dd67-751b-ef8c-387d16e9a456.png)
1. データを入れてやると正常に動作します。
    ```:sql
    INSERT INTO ICEBIRG_DEMO.PUBLIC.LINEITEM
    SELECT * FROM snowflake_sample_data.tpch_sf1.lineitem LIMIT 1
    ```
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/efd1e3b8-e4f3-df01-98c5-d37614f37d9f.png)
    データフォルダも確認できます。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/81537121-8ca8-6d70-1bab-2cf1cf2e6368.png)
    conversion ログも成功となっています。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/601d19e8-a913-6722-edd2-9066a6d6ad8a.png)

### 5. Power BI でのリアルタイム性の確認

まずは Power BI レポートで確認してみます。 Direct Lake を利用可能なので、即座にデータ反映されるかも試していきます。

1. SQL分析エンドポイントに切り替えて、レポートを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/16239aa1-c2a8-76b2-bd77-6d22031b8c77.png)
2. 細かい手順は割愛して、レポートができました。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/abec05c2-37cf-525f-f138-32a8f97a46c9.png)
3. データの反映時間の確認もやってみます。※ 時間短縮のため Snowflake 側は最高スペックで動かしました。
    6億行のデータが1分未満で Power BI に反映されました！
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/48435554-9fad-28e6-a65a-d684aca2eee6.png)
    https://www.youtube.com/watch?v=_JMeDyYqTIE
    
    Snowflake が書き込んだ Iceberg データを参照しているだけなので、V-Order は適用されていませんが、問題なく動きます
    ![2766ebb4d4763244b42a862a589fd7d9.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/052c9703-3ae0-de12-cecf-12f9d6fe3716.gif)

同期速度の秘訣は、Iceberg テーブル自体のデータの変換は発生していないことです。
あくまで Iceberg で管理されている Parquet ファイルを Delta Lake として読み替えるためのメタデータ（Delta Log ファイル）を生成することでフォーマットの読み替えを実現しています。
テーブル内のデータを格納している Parquet とは異なり、メタデータは大きなデータではないので高速に処理が可能となっています。

### 6. その他の分析エンジンでのデータ利用

#### T-SQL 

ショートカットされたテーブルはそのまま Fabric 上の T-SQLエンジンで分析が可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/08cc7cf3-1ca3-ee17-7506-9bde00522e59.png)

ビジュアルクエリを使えば ローコードで SQL 作成も可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/fbd141b3-046b-af21-017c-9f595921bafd.png)

#### Spark

ノートブックを使用して Pyspark による分析も可能です。現時点ではデータ型精度の問題が発生する場合があり、オプションをセットする必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/8b6e930b-c7ce-f7a5-28be-74079b068ee4.png)

## 制限事項

まだ多くの制限事項がある点に注意ください。

[制限事項と考慮事項](https://learn.microsoft.com/en-us/fabric/onelake/onelake-iceberg-tables#limitations-and-considerations)