Snowpipe x Azure Event Grid で自動データロードを試してみる

みなさん、こんにちは！

Snowpipe は Snowflake で提供されているデータロード機能です。ステージ（データ取り込み対象のストレージ）でファイルが利用可能になったタイミングでデータロードを行うことができます。

COPY コマンドを手動で実行する一括ロードと違い、**クラウドストレージのイベント通知や REST API による自動ロードを実現できる**という点が特徴です。

本記事では Snowpipe と Azure Event Grid を利用してデータロードを自動化する方法についてご紹介します。

※操作はすべて`ACCOUNTADMIN`ロールで行っています。

## 設定手順
設定手順は以下の通りです。

### 1. テーブル準備
Snowflake のワークシートで以下のSQLを実行し、テーブルemployeesの作成とロード用のCSVファイル形式csv_formatの作成を行います。
```ruby:qiita.rb
-- employeesテーブル作成
CREATE OR REPLACE TABLE employees (
  employee_id STRING,
  first_name STRING,
  last_name STRING,
  email STRING,
  department STRING,
  salary INTEGER
);

-- ファイル形式作成
CREATE OR REPLACE FILE FORMAT csv_format
  TYPE = 'CSV'
  FIELD_DELIMITER = ','
  SKIP_HEADER = 0;
```

### 2. ストレージへのアクセス構成
[こちら](https://www.reqtc.com/blog/snowflake.html)の記事を参考に、以下の設定を行います。

* ストレージアカウント作成
* ストレージ統合（`azure_int`）作成
* 外部ステージ（`ext_stage_azure`）作成

### 3. Event Grid サブスクリプション構成
Azure ポータルでストレージアカウントコンソールを開き、ファイルロード対象のストレージアカウントの「イベント」で「＋イベントサブスクリプション」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956386/9c7f9bbf-7621-48a5-a6a2-7efa6c63dfff.png)

基本設定で以下の項目を設定します。

* **名前**：イベントサブスクリプションの名前
* **システムトピック名**：イベント送信先となるシステムトピックの名前
* **イベントの種類のフィルター**：送信対象のイベント。今回はファイルのアップロード時にイベントを送信したいため、「Blob Created」を選択。
* **エンドポイントの種類**：「ストレージキュー」を選択
* **エンドポイント**：「エンドポイントの構成」をクリックして設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956386/4ae0a8d1-dfeb-4f3a-989b-021e7f0e3ce0.png)

エンドポイントの構成は以下のように設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956386/8595ee94-a191-4c7e-a6de-c3098c7fe7ce.png)

その他はデフォルト設定のままで「作成」をクリックします。

### 4. 通知統合作成
Snowflake で以下のSQLを実行します。
```ruby:qiita.rb
CREATE NOTIFICATION INTEGRATION azure_notification_int
  ENABLED = true
  TYPE = QUEUE
  NOTIFICATION_PROVIDER = AZURE_STORAGE_QUEUE
  AZURE_STORAGE_QUEUE_PRIMARY_URI = '<queue_URL>'
  AZURE_TENANT_ID = '<tenant_ID>';
```

`<queue_URL>`は対象ストレージアカウントの「データストレージ」→「キュー」を開き、上記で設定したキューのURLの値を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956386/af99f092-5b7c-48e0-87ec-38611aa6139e.png)

`<tenant_id>`は Azure ポータルから「Microsoft Entra ID」を開き、概要の「テナントID」で確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956386/7ee99594-17c8-4bcb-abf1-df5f9d3c239f.png)

### 5. ストレージキューへのアクセス許可
Snowflake で以下のSQLを実行します。
```ruby:qiita.rb
DESC NOTIFICATION INTEGRATION azure_notification_int;
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956386/32942ee3-6b8e-4475-bdbc-5c7cc6536b97.png)

実行結果の`AZURE_CONSENT_URL`のリンクをクリックします。

アクセス許可画面にリダイレクトされるので、「承諾」をクリックします。
これにより、Snowflake がストレージキューにアクセスするためのアプリケーションが作成されます。

次に、アプリケーションにストレージキューに対するロールを付与します。

対象ストレージキューの「アクセス制御（IAM）」を開き、「追加」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956386/c6bb49c6-70b1-483a-b489-1d85902c868b.png)

ロールの割り当ての追加で、「ストレージキューデータ共同作成者」を選択し「次へ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956386/ff603ea1-b88d-48ef-8987-f188441c8529.png)

「メンバーを選択する」をクリックし、`AZURE_MULTI_TENANT_APP_NAME`に記載のアプリケーションを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956386/ace2d94c-0ff7-4b47-9bde-b48587b71ee2.png)

「レビューと割り当て」をクリックして完了です。

### 6. パイプ作成
Snowflake で以下のSQLを実行します。
```ruby:qiita.rb
CREATE PIPE test_pipe
  AUTO_INGEST = true
  INTEGRATION = 'AZURE_NOTIFICATION_INT'
  AS
    COPY INTO employees
      FROM @ext_stage_azure
      FILE_FORMAT = csv_format;
```

`test_pipe`という名前のパイプを作成するコマンドです。AS句以降に指定した COPY コマンドが、`AZURE_NOTIFICATION_INT`から通知を受け取ったタイミングで実行されます。

作成したパイプの詳細はデータベース管理画面から確認することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956386/18f78738-732e-44ef-94ad-aee0f8996619.png)

以上でパイプの設定は完了です。

## 動作確認
以下の`employees`テーブルに追加データをロードしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956386/94728d1d-dd4c-4109-86a3-29353868d994.png)

Azure ポータルから対象ストレージアカウントのコンテナにCSVファイル`employees_2.csv`をアップロードします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956386/06a9b82b-da5f-4061-8872-8efc1aa58f06.png)

CSVファイルの内容は以下の通りです。
```
1006,David,Wilson,david.wilson@example.com,Engineering,72000
1007,Susan,Martinez,susan.martinez@example.com,Marketing,68000
1008,Robert,Garcia,robert.garcia@example.com,Sales,71000
1009,Linda,Anderson,linda.anderson@example.com,HR,59000
1010,James,Thomas,james.thomas@example.com,Finance,82000
```

アップロード後、パイプが作動してテーブルにデータが取り込まれたことを確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956386/948d6edc-3990-4426-8c0a-025898de2645.png)

## さいごに
Snowpipe を利用すると、特定の場所にアップロードされたファイルのデータを自動的にテーブルに取り込むことができます。

パイプによりデータロードが自動化できることに加え、イベント通知やAPIリクエストがあったタイミングのみパイプが実行されるため運用コストも最小限に抑えることができます。

今回ご紹介したのは Azure の場合のみですが、AWS や Google Cloud でも同様にデータロードを自動化することが可能です。お使いの環境や要件に応じて、利用を検討してみてください。

## 参考
* [Snowpipe | Snowflake Documentation](https://docs.snowflake.com/ja/user-guide/data-load-snowpipe-intro)
* [ポータルを使用した Azure Event Grid サブスクリプション - Azure Event Grid](https://learn.microsoft.com/ja-jp/azure/event-grid/subscribe-through-portal)