【Snowflake】ネイティブアプリを作ってみよう(基本編)

【Snowflake】ネイティブアプリを作ってみよう(基本編) | Tableau-id Press -タブロイド-
snowflake_logo

おひさしぶりです、やしろです。
ちょっと最近ブログご無沙汰気味だったのですが、色々書きたいネタは溜まっているので頑張って書いていこうと思ってます。

今回は、Snowflakeのネイティブアプリの作り方について改めてご紹介したいと思います。
2回に分けてご紹介予定でして、今回は基本編です。
公式ドキュメントにあるチュートリアルを公式よりちょっと丁寧に解説してみたので、ネイティブアプリを作ったことがない方でも躓くことなくアプリを作れるのでは、と思ってます。
長編ですが、よければトライしてみてください!

1.基本的な設定

1.Snowflake CLIについて

このチュートリアルではSnowflake CLIを使用します。
Snowflake CLIとは、Snowflakeが提供するコマンドラインツールです。
モジュールやスクリプトでカスタマイズや拡張が可能なのでニーズや好みに合わせて調整しやすく、Snowflake によるアプリケーション(Streamlit、Snowpark Container Services など:以下APP)開発での使用などに非常に適しています。
Snowflake CLIの詳細な設定は公式ドキュメントをご確認ください。

構成ファイル(config.toml)に、今回使用するトライアルアカウントの接続情報を追加して保存しておきましょう。

2.仮想環境作成

CLIツールを立ち上げて、今回のチュートリアル用の仮想環境を作成しましょう。(私はAnacondaを使用しました)

3.初期化

ローカルファイルシステムでSnowflake Native APPプロジェクトを初期化します。
Snowflake Native APPのファイルを保存しておく任意のディレクトリに移動して、Snowflake CLIを使って次のコマンドを実行します。

snow init --template app_basic tutorial

このコマンドを実行すると、該当のディレクトリに以下のようにファイルが生成されます。

ここから、各ファイルの中身を作成していきましょう。

app/setup_script.sqlファイル
このファイルに現時点で保存しておくスクリプトはないのですが、空のまま保持できないようなのでプレースホルダーとして次のようなコメントアウトした文字列を入れておきます。

-- Setup script for the Hello Snowflake! app.

app/README.mdファイル
これはAPPの概要を説明するファイルで、Snowsightでアプリを開いたときにはこのREADMEに記載した内容が表示されます。

This is the readme file for the Hello Snowflake app.

app/manifest.ymlファイル
このファイルには、APPのメタデータと構成パラメーターが含まれており、APP実行時の動作に影響を与えます。
また、セットアップスクリプトや他ファイルへのパスはこのファイルの場所が基準となっています。ファイル名は必ずmanifest.ymlである必要があるので、勝手に変更しないよう注意してください。
setup_scriptはセットアップスクリプトファイルへの相対パスを記載します。readmeも同様です。
デフォルトでは同じappフォルダ内に生成されるので、ファイル名を記載すればOKです。

manifest_version: 1
artifacts:
    setup_script: setup_script.sql
    readme: README.md

snowflake.ymlファイル
これはSnowflakeにデプロイするオブジェクトについて記述したプロジェクト定義ファイルです。マニフェストファイル同様、ファイル名は必ずsnowflake.ymlである必要があります。

definition_version: 2
entities:
   hello_snowflake_package:
      type: application package
      stage: stage_content.hello_snowflake_stage
      manifest: app/manifest.yml
      artifacts:
         - src: app/*
           dest: ./
   hello_snowflake_app:
      type: application
      from:
         target: hello_snowflake_package
      debug: false

上の記述では、entities以下でSnowflakeに作成される各オブジェクトの名称を定義しています。
・APPパッケージ名:hello_snowflake_package
・APP名:hello_snowflake_app
・APPを保持するステージ名:stage_content.hello_snowflake_stage
artifactsセクションでは、ステージングするファイルを指定しています。ここでは、appフォルダ配下にあるファイルすべてをステージングする設定になっています。

2.ストアドプロシージャ作成

いよいよAPPパッケージの作成に入りましょう。まずは、”Hello Snowflake!”を出力するストアドプロシージャを作成してみます。

1権限設定

まず、SnowflakeでAPPパッケージを作成するための権限をロールに付与します。チュートリアルではサンプルとしてACCOUNTADMINに付与するコードが紹介されています。
こちらはSnowflake CLIで実行して付与します。

snow sql -q "GRANT CREATE APPLICATION PACKAGE ON ACCOUNT TO ROLE accountadmin" -c tut1-connection --config.tomlファイルで設定した、今回使用するコネクション名を-cに記載

※このコマンドは、公式のチュートリアルにはシングルクォーテーションで記載されていたのですが、ダブルクォーテーションに置き換えないとエラーになるので注意してください。

実は、ACCOUNTADMINにはデフォルトで付与されている権限なのでこのコマンドを実行する必要はありません。
実運用する際には、APPパッケージはACCOUNTADMINではなく適切な権限を持つロールで作成するのが一般的なので、上記のコマンドのロールを置き換えて実行しておく必要があります。
今回は以下のコマンドに置き換えて実行して、以降の設定を TUTORIAL1_ROLEで実施してみました。

snow sql -q "GRANT CREATE APPLICATION PACKAGE ON ACCOUNT TO ROLE TUTORIAL1_ROLE" -c tut1-connection
snow sql -q "GRANT CREATE APPLICATION ON ACCOUNT TO ROLE TUTORIAL1_ROLE" -c tut1-connection

APPパッケージ作成の権限設定ができたところで、いよいよAPPの中身を作成していきます。
早速セットアップファイルにコードを記載していきましょう。
まず、以下のコードをsetup_script.sqlに記載します。

CREATE APPLICATION ROLE IF NOT EXISTS app_public;
CREATE SCHEMA IF NOT EXISTS core; 
GRANT USAGE ON SCHEMA core TO APPLICATION ROLE app_public;

ここで行っていることは次の3つです。
・APPロール app_publicの作成
・スキーマhello_snowflake_app.coreの作成
・APPロールapp_publicの、スキーマhello_snowflake_app.coreに対するUSAGE権限の付与
APPロールとは、APPのコンテキスト内でのみ使用できるロールです。データ共有後にコンシューマーアカウントで作成される、APPオブジェクトへのアクセス権設定のために必要となります。
スキーマcoreには、これから作成するストアドプロシージャを格納していきます。

2ストアドプロシージャの作成

さて、ではストアドプロシージャの作成に入ります。次のように、ストアドプロシージャを作成するためのコードを記載しましょう。

CREATE OR REPLACE PROCEDURE CORE.HELLO()
 RETURNS STRING
 LANGUAGE SQL
 EXECUTE AS OWNER
 AS
 BEGIN
 RETURN 'Hello Snowflake!';
END; 

このストアドプロシージャに限った話ではないのですが、オブジェクトを記載するときに必ずスキーマを明記する必要があるので注意してください。
続いて、先ほど作成したAPPロールapp_publicに、ストアドプロシージャのUSAGE権限を付与します。setup_script.sqlの最後に、こちらのクエリを追加しておきます。

GRANT USAGE ON PROCEDURE core.hello() TO APPLICATION ROLE app_public;

3パッケージファイルのステージングとAPPの作成

ここまできたらAPPの作成準備が完了です。以下のSnowflake CLI コマンドを実行しましょう。

snow app run -c tut1-connection

APPパッケージの作成からデプロイ、APP作成まで、このコマンド一つで一気に実行してくれます。
キャプチャのように、各ファイルがaddedされていることが確認取れればOKです。

試しに、CLIでプロシージャを実行してみましょう。次のコマンドを実行してみてください。

snow sql -q "call hello_snowflake_app.core.hello()" -c tut1-connection

このように、Hello Snowflakeが出力されるはずです。ここまで出来たらAPPの作成が成功です。
せっかくなのでSnowsightからも確認してみましょう。
Snowsightにログインして、TUTORIAL1_ROLEに切り替えます。
"データ製品 > アプリ"と遷移してみると、先ほどデプロイしたhello_snowflake_appがインストールされていることが確認できます。

また、データタブからデータベースにアクセスすると、他のデータベースと並んでhello_snowflake_packageとhello_snowflake_appが表示されています。
こちらから、スキーマやその配下のオブジェクトを確認することもできます。

ステージングされたファイルは、SQLワークシートにて次のコマンドを実行することで確認できます。

USE ROLE TUTORIAL1_ROLE; 
LIST @hello_snowflake_package.stage_content.hello_snowflake_stage;

また、次のコードは作成したプロシージャ hello_snowflake_app.core.helloを実行します。

CALL hello_snowflake_app.core.hello();

3APPにデータコンテンツを追加

1テーブルの作成

ここからは、テーブルを作成してサンプルデータをインサート、データコンテンツとしてアプリと共有する方法を学びます。
APP内に新たにスキーマとテーブルを作成して、それらに権限を付与することでデータの共有が可能になります。
まず、tutorial/scriptsフォルダを作成、その中にshared_content.sqlファイルを作成します。
sqlファイルの中には、以下のスクリプトを記載しておきましょう。

USE APPLICATION PACKAGE <% ctx.entities.hello_snowflake_package.identifier %>; 
CREATE SCHEMA IF NOT EXISTS shared_data; 
USE SCHEMA shared_data; 
CREATE TABLE IF NOT EXISTS accounts (ID INT, NAME VARCHAR, VALUE VARCHAR); 
TRUNCATE TABLE accounts; 
INSERT INTO accounts VALUES
 (1, 'Joe', 'Snowflake'),
 (2, 'Nima', 'Snowflake'),
 (3, 'Sally', 'Snowflake'),
 (4, 'Juan', 'Acme');
 -- grant usage on the `ACCOUNTS` table 
GRANT USAGE ON SCHEMA shared_data TO SHARE IN APPLICATION PACKAGE <% ctx.entities.hello_snowflake_package.identifier %>; 
GRANT SELECT ON TABLE accounts TO SHARE IN APPLICATION PACKAGE <% ctx.entities.hello_snowflake_package.identifier %>;

ここの記載で実行しているのは以下です。
・スキーマ hello_snowflake_package.shared_dataの作成
・テーブルhello_snowflake_package.shared_data.accountsの作成
・スキーマ hello_snowflake_package.shared_data・テーブルhello_snowflake_package.shared_dataへのAPPパッケージの権限付与
ちなみに、<% ctx.entities.hello_snowflake_package.identifier %>というのは、snowflake.ymlファイルに記載したapplication packageの識別子に置き換えるテンプレートです。

APPを共有する必要がある場合、この権限設定がきちんと行われていないとコンシューマ側でAPPが正常に動作しないので注意してください。
APP内のスキーマごとにUSAGE 権限をAPPパッケージに付与したうえで、共有するスキーマ内のオブジェクトに SELECT 権限を付与する必要があります。
shared_content.sqlが記載できたら、snowflake.ymlファイルに、post-deploy – sql_scriptsとして次のように記載しておきましょう。
これで、APPが更新されるたびにこのスクリプトが実行されるようになります。

2ビューの作成

更にコンテンツを充実させていきましょう。
先ほど作成したテーブルhello_snowflake_package.shared_data.accountsを元にしたビューを作成するスクリプトを、shared_content.sqlファイルの最後に追加します。

CREATE OR ALTER VERSIONED SCHEMA code_schema; 
GRANT USAGE ON SCHEMA code_schema TO APPLICATION ROLE app_public; 
CREATE VIEW IF NOT EXISTS code_schema.accounts_view 
 AS SELECT ID, NAME, VALUE 
FROM shared_data.accounts; 
GRANT SELECT ON VIEW code_schema.accounts_view TO APPLICATION ROLE app_public;

ここでは
・バージョン管理されたスキーマhello_snowflake_app.code_schemaの作成
・スキーマhello_snowflake_app.code_schemaへのAPPロールapp_publicのUSAGE権限の付与
・ビューhello_snowflake_app.code_schema.accounts_viewの作成ビューhello_snowflake_app.code_schema.accounts_viewへのAPPロールapp_publicのSELECT権限付与

を実行しています。
code_schemaはバージョン管理されたスキーマにしていますが、これは次項のUDF作成のところで解説します。
APPロールに権限を付与することで、コンシューマー側でAPPをインストールした際にAPPロールを(意識はせずとも)使用して、ビューを表示させることが可能になります。

3アプリのテスト

さて、データコンテンツを追加する準備が整いましたね。APPをアップデートしてテストしてみましょう。
APPパッケージとAPPオブジェクトのアップデートに使用するコマンドはこちらです。

snow app run -c tut1-connection

最初のデプロイと同じコマンドを実行することで、アップデートも行うことが出来ます。
ちなみに共有済みのAPPパッケージに関しても、コンシューマーアカウントにインストール済みのAPPパッケージとAPPオブジェクトまでこのコマンド一つで更新してくれます。
非常にプロバイダーフレンドリーなコマンドですね。
Application successfully upgraded.と表示されればアップグレード完了です。

更新したAPPに作成したビューに問題なく動作するか、CLIから以下のコマンドを実行して確認してみましょう。

snow sql -q "SELECT * FROM hello_snowflake_app.code_schema.accounts_view" -c tut1-connection

きちんとデータが表示されましたね。
Snowsightから確認してみると、hello_snowflake_package.shared_data.accountsと

hello_snowflake_app.core_schema.accounts_viewがちゃんと追加されていることが確認できますね。

ワークシートに移動してクエリも実行してみましょう。

SELECT * FROM hello_snowflake_app.code_schema.accounts_view;

4Pythonスクリプトの作成

次に、Pythonスクリプトの追加に挑戦します。Pythonコードを追加することで、APPの機能拡張が可能になります。
このチュートリアルでは、次の2種類のPythonコードを使用します。
・セットアップスクリプト内で完結するインラインPython UDF
・セットアップスクリプトの外部にあるPythonファイルを参照するPython UDF
それぞれの方法には次のような特徴があるので、使用したい場面によって使い分けるといいでしょう。

特徴 インライン型 外部参照型
開発の早さ
コードの整理
再利用
複雑処理への適性 △(簡易処理向け) ◎(複雑ロジックOK)
デプロイの楽さ ◎(単体で完結) △(artifacts管理が必要)

1インラインPython UDFの追加

まずはインラインPython UDFを追加してみましょう。Python関数をUDFとして直接セットアップスクリプトに記述するだけです。
以下のコードをsetup_scripts.sqlの最後に記載しましょう。

CREATE OR REPLACE FUNCTION code_schema.addone(i int) 
RETURNS INT 
LANGUAGE PYTHON  
RUNTIME_VERSION = '3.11' 
HANDLER = 'addone_py' 
AS 
$$ 
def addone_py(i): 
return i+1 
$$; 

GRANT USAGE ON FUNCTION code_schema.addone(int) TO APPLICATION ROLE app_public;

ここで実行しているのは次の2つです。
・UDF code_schema.addone(i int)の作成
・APPロールapp_publicのUDF code_schema.addone(i int)へのUSAGE権限の付与
前項でcode_schemaを作成するときに、”バージョン管理されたスキーマ”として作成しましたが、その理由がここにあります。
というのも、UDFは通常のスキーマだとAPPのアップグレード時の同時コード実行でエラーとなってしまうので、バージョン管理されたスキーマで定義する必要があるのです。

2外部Pythonモジュールの追加

もう一つのUDF追加方法も試してみましょう。再びsetup_scripts.sqlに、以下のコードを追加します。

CREATE or REPLACE FUNCTION code_schema.multiply(num1 float, num2 float) 
RETURNS float 
LANGUAGE PYTHON RUNTIME_VERSION = 3.9 
IMPORTS = ('/python/hello_python.py') 
HANDLER='hello_python.multiply'; 

GRANT USAGE ON FUNCTION code_schema.multiply(FLOAT, FLOAT) TO APPLICATION ROLE app_public;

スキーマcode_schemaにUDFを作成し、APPロールapp_publicに権限を付与しているのは先程と同様ですが、名前付きステージに作成する外部Pythonファイルhello_python.pyを参照する IMPORTS 句が含まれているところに注意です。
tutorialフォルダ配下にpython/hello_python.pyファイルを作り、以下を記述しておきましょう。

def multiply(num1, num2): 
return num1*num2

これはセットアップスクリプトで定義されたインライン関数と一致しています。

最後に、Snowflake.ymlのartifactsセクションに次のスクリプトを追加すれば完了です。

- python/hello_python.py

3APPのインストール・テスト

さて、作成したUDFが問題なく動くかテストしてみましょう。
まずは以下のコマンドでAPPのインストールまで実行します。

snow app run -c tut1-connection

インストールできたら、CLIから次のコマンドを実行してみましょう。

snow sql -q "SELECT hello_snowflake_app.code_schema.addone(1)" -c tut1-connection

先に作成したインラインUDFが正常に作動すると、次のような結果が得られます。

同様に、次のコマンドも実行してみましょう。

snow sql -q "SELECT hello_snowflake_app.code_schema.multiply(1,2)" -c tut1-connection

こちらは、外部Pythonモジュールを参照たUDFのテストです。次のように表示されればOKです。

5Streamlitの作成

さて、ここまででだいぶAPPの中身が充実してきましたね。このセクションではいよいよ、Streamlitを使ってAPPのインターフェイスを作成していきます。
その前に、Streamlitとはなにか?について簡単に説明しておきましょう。

1Streamlitとは

Streamlit は、Pythonだけで簡単にWebアプリを作れるオープンソースのフレームワークです。
データ分析や可視化の結果を、コード数行でインタラクティブなWebアプリとして表示できます。特徴としては次のとおりです。
・Web開発の知識がなくても、PythonだけでUIが作れる
・PandasやPlotlyなどのデータツールと相性抜群
・アナリストやデータサイエンティストに人気
要は、Pythonだけで作れる手軽なWebアプリケーションだと理解していただければ大丈夫です。

2Streamlit in Snowflakeとは

Streamlit in Snowflake は、Snowflake上に直接Streamlitアプリを組み込んで動かせる機能です。
Snowflake社が2022年3月にStreamlit社を買収したことにより開発が加速された機能で、2023年12月にGA(一般提供開始)されています。
Snowflakeの上でそのままアプリを動かすことができるので、以下のような利点があります。

  1. データ移動ゼロ:Snowflake内で直接可視化・操作可能
  2. セキュリティ統合:Snowflakeのロール・権限をそのまま活用
  3. アプリケーション化:ネイティブアプリとして他部門や他社に提供可能
    上記の理由から、StreamlitはSnowflakeのネイティブAPPユーザーインターフェイスとして非常に適しているのです。
    今回まさにこの「3. アプリケーション化」機能を活かして、APPを仕上げていきます。

    3Streamlitファイルを作成

    さて、では作成していきましょう。まずはStreamlitファイルの作成です。
    tutorialフォルダ配下にstreamlit/hello_snowflake.pyファイルを作成しましょう。
    ファイルの中には以下の記述をしてみてください

# Import python packages
import streamlit as st
from snowflake.snowpark import Session

# Write directly to the app
st.title("Hello Snowflake - Streamlit Edition")
st.write(
"""The following data is from the accounts table in the application package.
However, the Streamlit app queries this data from a view called
code_schema.accounts_view.
"""
)

# Get the current credentials
session = Session.builder.getOrCreate()

# Create an example data frame
data_frame = session.sql("SELECT * FROM code_schema.accounts_view")

# Execute the query and convert it into a Pandas data frame
queried_data = data_frame.to_pandas()

# Display the Pandas data frame as a Streamlit data frame.
st.dataframe(queried_data, use_container_width=True)

各処理にもコメントが入っていますが、このコードはhello_snowflake_appに格納されたビューcode_schema.accounts_viewを、 Streamlitにて表形式で見せるためのコードとなっています。
ファイルを保存したら、Pythonコードと同様にSnowflake.ymlのartifactsセクションに以下のスクリプトを追加します。

- streamlit/hello_snowflake.py

最後に、Streamlitを作成するためのスクリプトをsetup_scripts.sqlファイルに追加します。

CREATE STREAMLIT IF NOT EXISTS code_schema.hello_snowflake_streamlit 
FROM '/streamlit' 
MAIN_FILE = '/hello_snowflake.py' ;

GRANT USAGE ON STREAMLIT code_schema.hello_snowflake_streamlit TO APPLICATION ROLE app_public; 

Streamlit code_schema.hello_snowflake_streamlitの作成と、APPロールapp_publicのStreamlitへの権限付与のコードです。
setup_scripts.sqlファイルの末尾に追加しておけばOKです。

4APPのインストール・テスト

では、これまでと同様の手順でAPPパッケージとAPPを更新しましょう。次のコマンドを実行します。

snow app run -c tut1-connection

このコマンドを実行すると、Snowflake上のAPPに直接アクセスできるURLが出力されます。
このURLにアクセスすると、APP名の右隣に”hello_snowflake_streamlit”とStreamlitの名称が表示されます。
そちらをクリックすると以下のようなStreamlit画面が表示されるのが確認できます。

6アプリのバージョン管理

これまでは、”ステージ開発”モードを使用して変更をプッシュしてきました。
ステージ開発モードは、バージョン管理不要でその分アプリ開発を迅速に反復できる、というメリットがあるのですが、APPパッケージを他のSnowflakeユーザーと共有するにはAPPのバージョンを作成する必要があるので、要注意です。
ちなみに、チュートリアルでは別アカウントへのデータ共有まで解説がありましたが、トライアルアカウントでは外部アカウントへのアプリ共有はサポートされていないので、今回は割愛します。
次回のブログでは、本アカウントを使ってアプリ共有までご紹介予定です。

1APPパッケージへのバージョン追加

APPパッケージにバージョンを追加するには以下のコマンドをCLIにて実行します。

snow app version create v1_0 -c tut1-connection

続いて次のコマンドを実行して、バージョンに基づいてアプリをインストールしましょう。

snow app run --version V1_0 -c tut1-connection

このコマンドを実行すると、プロンプトにAPPを作り直すか問われるので、”y”と答えます。
というのも、バージョンを使用してAPPをアップグレードするには既存のAPPを削除し、このバージョンで再作成する必要があるのです。
実は次回のオリジナルアプリ作成で、一部権限付与がsetup_scripts.sql内ではうまく行かなかったので、開発段階ではSnowsightのワークシートを併用していました。
しかし、いざバージョンを付与しようとしたときに途中にSnowsightのコマンドを挟めないためエラーが起こる、という事象に苦しめられました。
最終的に解決したのでそちらのコマンドをご紹介させていただいていますが、思わぬ落とし穴でした。
共有する想定でアプリを作成されるときは、バージョン管理が必須ということをくれぐれも覚えておいてください。

7まとめ

さて、ここまでチュートリアルに沿ってNativeAPPを作成してきましたが、いかがだったでしょうか。
このチュートリアルでは、Snowflakeネイティブアプリの開発をゼロから構築する流れを、段階的に学んできました。
Snowflake CLIの基本設定や仮想環境の構築から始まり、ストアドプロシージャやPython UDF、データの公開、そしてStreamlitによるインターフェイス構築に至るまで、実際の開発フローを通して、NativePPの全体像をざっくりと把握することができたと思います。
特に、Streamlit in Snowflake の登場により、データの可視化や操作をアプリケーションに組み込むハードルは大きく下がりました。
これにより、コードとデータを分離せずに、エンドユーザーにインタラクティブな体験を提供できる柔軟性が実現されています。
今後、NativeAPPを展開する際には、今回学んだ「APPパッケージ」「APP」「ロールと参照権限」「ステージとデプロイ」の構成が基盤になってきますので、ぜひとも理解を深めていただきたいところです。
次回のブログでは、もう少し実用性を兼ね備えたサンプルアプリについてご紹介していきたいと思います。

truestarでは、Snowflake導入検討、導入支援や環境構築まで幅広くサポート可能です。
Snowflakeに゙興味がある、導入済みだけどもっとうまく活用したい等々ありましたら、ぜひこちらから相談ください!

また、truestarではSnowflake Marketplaceにて、加工済みオープンデータを無償提供するPrepper Open Data Bank、全国の飲食店の情報を集めたデータセットの販売を行っております。(サービスリンク

これまでのSnowflakeに関する記事はこちら