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

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

やしろです。

前回、ネイティブアプリを作ってみよう(基本編)ということで、チュートリアルに沿ってサンプルアプリを作成してみました。
今回は、オリジナルアプリの作成に挑戦するのですが、セキュアビューを用いてデータの共有まで行ってみます。
併せて、セキュアビューを用いてアプリを作成するときのポイントや、メリットなどについてご紹介していきたいと思います。
なお、ネイティブアプリの共有は無料アカウントではサポートされていないため、今回のアプリ作成には正式版のアカウントを使用しています。実際に共有までトライしてみたい方は、本番環境の利用をご検討いただければと思います。

テーブルへの接続

今回作成するのは、「どこで有給を1日取得すれば、もっとも長い連休になるか」を見つけるアプリです。
そのためにはまず、カレンダー上の祝日や週末などの情報を正しく取得し、アプリで使えるようにする必要があります。
ですので最初に、Snowflakeに保存されているテーブルに接続する方法を紹介します。

Snowflakeでは、さまざまなデータソースにある情報をテーブルという形で管理しています。
ネイティブアプリでは、これらのテーブルにアクセスすることで、必要なデータを取り込み、可視化や分析に活用できます。
ここでは、次のことを行います:
・祝日データが格納されたテーブルにアクセスする
・どのような列(カラム)が含まれているかを確認する
・アプリが使いやすいように必要な列だけを抽出する
次のセクションでは、これらのデータを他のユーザーにも安全に共有するための「Secure View(セキュアビュー)」という仕組みについても紹介します。
まずは、アプリの出発点となる「データとの接続」から始めてみましょう。

1アプリの初期化

前回のブログの1-1、1-2を参考に初期のセットアップを実行します。
今回は弊社の本番環境を使用するため、前章とは異なる接続情報を用いる必要がありました。
ですので、config,tomlに新たな接続情報を追記してあります。今回はこちらの接続を使用していきます。

その他、基本的に前章の手順に沿って同じように記述していけばOKですが、Snowflake.ymlファイルは以下のように設定しておきます。

definition_version: 2
entities:
  holidays_pkg:
    type: application package
    stage: stage_content.holidays_stage
    manifest: app/manifest.yml
    artifacts:
      - src: app/*
        dest: ./    
  holidays_app:
    type: application
    from:
      target: holidays_pkg
    debug: false

2カレンダーデータの準備

次にカレンダーデータを準備していきましょう。今回利用するのは、弊社truestarが提供する”PODB_CALENDAR_DATA”です。ここで、truestarの展開しているサービス「PODB」についてご紹介させてください。
「Prepper Open Data Bank」(PODB)とは、株式会社truestarが提供する「収集・加工不要ですぐに使えるオープンデータ」サービスです。
e-Statや国土数値情報などの公的なオープンデータを、Snowflake マーケットプレイス上で即座に分析できる形に整形・無償提供しています。
e-statの統計データや気象データ、鉄道路線のデータなど、様々なオープンデータをご用意しています。
今回は、この中でも一番ユーザーの多いカレンダーデータを使っていこうと思います。

1マーケットプレイスでデータの取得

マーケットプレイスには、Snowsightからログインしてアクセスします。デフォルトではACCOUNTADMINロールが必要になるので切り替えておきましょう。
なお、今回のアプリ作成は便宜的にすべてACCOUNTADMINを使用して進めますが、実務の場面では適宜必要な権限を付与したロールに切り替えて作業することを強くオススメします。
データ製品>マーケットプレイスにアクセスしてみると、マーケットプレイスで共有されている様々なデータやネイティブアプリを確認することが出来ます。
検索窓に”PODB”と入力するとPODBが提供するデータが複数ヒットするので、”Japanese Calendar Data”を選択します。
次キャプチャのような詳細画面が表示されるので、右上の”取得”をクリックしましょう。

するとこのようなダイアログボックスが立ち上がります。
オプション項目では、DB名の変更とほかロールへのアクセス権の付与を行うことが出来ます。
今回は、デフォルトの名称が少々長いので「PODB_CALENDAR_DATA」と変更しておきました。

2テーブルの作成

マーケットプレイスから取得したような共有データは読み取り専用で、いくつかの制限事項があるのですが、その中に”他のアカウントへの再共有は不可”という制約があります。
ですので、今回のアプリのように共有前提で使用するためには一度実テーブルを作成してあげる必要があります。
SQLワークシートで次のクエリを実行して、テーブルを作成しておきましょう。元のデータは2010年から入っているのですが、今回は2024年から2026年に絞って作成しました。

//データベースとテーブルの作成 
CREATE DATABASE podb_calendar_data_t; 
CREATE OR REPLACE TABLE podb_calendar_data_t.public.calendar_data 
 AS SELECT * 
FROM podb_calendar_data.e_podb.e_japan_calendar 
WHERE DATE >= DATE '2024-01-01'; 

//テーブルが作成されているか確認 
SELECT * FROM podb_calendar_data_t.public.calendar_data;

次のキャプチャのようにデータが表示されれば準備完了です。

SECURE VIEWを使ったデータの共有

データの共有は、ビジネスにおけるコラボレーションや意思決定を加速させるために不可欠な要素ですが、データの機密性を守ることはその過程で最も重要な課題のひとつです。
特に個人情報や機密データを扱う場合、データの公開や共有が安全であることを保証するためには、しっかりとしたセキュリティ対策が求められます。
ここでは、さきほど作成したテーブルをもとにしたビューを使い、ネイティブアプリを作成してきます。
セキュアビューは、特定のデータに対するアクセスを制御し、権限を持つユーザーだけが必要な情報にアクセスできるように構築されています。
これにより、データを安全に共有しながら、機密情報が不正に漏洩するリスクを最小限に抑えることができます。

1なぜセキュアビューなのか

先程簡単に言及しましたが、データの共有を前提としたアプリ作成にはセキュアビューを用いることが大切です。
主な理由は次の2つです。
・データのセキュリティの担保
・データ更新の簡便性
そもそもセキュアビューではビューの定義と詳細は公開しません。ビューの基になるテーブルや内部構造をマスキングしながら、コンシューマーに必要な情報だけを提供できます。
これにより、プロバイダーはデータのセキュリティを保ちながら、安全に共有することができます。
また、ビューとして共有することで、元のテーブルやデータセットを更新すれば、その変更は即座に反映されます。
ビュー自体を手動で更新する必要はなく、元データが更新されるたびに、アクセスするユーザーが最新のデータを確認できるようになります。
これはコンシューマに共有したあとも同様で、コンシューマ側で特別な操作を行うことなく、常に最新のデータが即時で反映される環境を簡単に提供することが出来るのです。
このように、ネイティブアプリを共有するのにはセキュアビューを用いた構成が非常に適している、ということがお分かりいただけるかと思います。

2アプリの作成

さて、では実際にセキュアビューを用いたアプリを構築していきましょう。

1権限設定

前回の”2-1権限設定”を参考に、このアプリも権限設定を行っていきます。まず、以下のコードを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;

今回このスキーマcoreはSteramlitを格納するのに使用します。

2セキュアビューの作成

続いて、セキュアビューを作成するために新しいファイルを準備していきます。tutorial/scripts/fetch_data.sqlというファイルを作成しましょう。

このファイルの中身を記載していく前に、snowflake.ymlを編集しておきます。
新たに”meta”セクションを作成し、“post_deploy”として登録しておきます。これで、アプリパッケージholidays_pkgが作成されたあとに、fetch_data.sqlファイルに記載したスクリプトが実行されるようになります。

definition_version: 2
entities:
  holidays_pkg:
    type: application package
    stage: stage_content.holidays_stage
    manifest: app/manifest.yml
    artifacts:
      - src: app/*
        dest: ./
    meta:  
      post_deploy:
      - sql_script: scripts/fetch_data.sql    
  holidays_app:
    type: application
    from:
      target: holidays_pkg
    debug: false

では、ymlファイルを更新したところでfetch_data.sqlのスクリプトを記載していきます。
まずは作成されたアプリパッケージに、ビューを保存するためのスキーマcalendar_schemaを作成し、ビューの参照元としたいテーブルへの権限を付与します。

USE APPLICATION PACKAGE holidays_pkg; 
CREATE SCHEMA IF NOT EXISTS calendar_schema; 

USE SCHEMA calendar_schema; 
GRANT REFERENCE_USAGE ON DATABASE podb_calendar_data_t TO SHARE IN APPLICATION PACKAGE holidays_pkg;

パッケージ自体に参照権限を付与することで、パッケージ内部にセキュアビューを作成することが可能になります。
そのセキュアビューを作成するためのスクリプトがこちらです。

CREATE OR REPLACE SECURE VIEW calendar_schema.holidays_view 
AS SELECT
 date
 ,weekday
 ,holiday_name
 ,is_sat_sun
 ,is_holiday
 ,is_consecutive_days_off
 ,is_day_before_hol
 ,number_of_consec_hol_excl_today 
FROM podb_calendar_data_t.public.calendar_data; 

GRANT USAGE ON SCHEMA calendar_schema TO SHARE IN APPLICATION PACKAGE holidays_pkg; 
GRANT SELECT ON TABLE calendar_schema.holidays_view TO SHARE IN APPLICATION PACKAGE holidays_pkg;

1-2で作成したテーブルをもとに、アプリに必要なカラムに絞ったセキュアビュー"calendar_schema.holidays_view"を作成しています。
ちょっとややこしいのですが、アプリパッケージ内に作成したスキーマとビューに対しても、明示的にアプリパッケージに権限を付与してあげないとアクセスできないので、必ず権限付与のスクリプトもセットで実行します。

3Streamlitの作成

ビューが作成できたら、次はアプリのインターフェイスとなるStreamlitの構築です。
まずは "tutorial/streamlit" フォルダと "tutorial/streamlit/holidays.py" というファイルを作成します。
ファイルの中身は次のとおりです。

import streamlit as st
import pandas as pd
import snowflake.connector
import calendar
from snowflake.snowpark.context import get_active_session

# セッションとデータ取得
session = get_active_session()
df = session.table("CALENDAR_SCHEMA.HOLIDAYS_VIEW").to_pandas()

# 日付列をdatetime型に変換
df["DATE"] = pd.to_datetime(df["DATE"])

# 休み判定列の作成(祝日 or 土日)
df["IS_REST"] = df["IS_HOLIDAY"] | df["IS_SAT_SUN"]
df = df.sort_values("DATE").reset_index(drop=True)

# 年列を追加(年選択のため)
df["YEAR"] = df["DATE"].dt.year

# Streamlit UI - 年選択(1つだけ)
years = sorted(df["YEAR"].unique())
selected_year = st.selectbox("📅 年を選んでください", years, index=0)

# 選択された年のデータに絞る
df_year = df[df["YEAR"] == selected_year].copy().reset_index(drop=True)
df_year["ID"] = range(len(df_year))

# 有給候補(休みでない平日)
paid_leave_candidates = df_year[~df_year["IS_REST"]]

# 指定行を仮に有給にして連休日数を返す関数
def calc_consecutive_holiday_length(df, leave_index):
    temp_df = df.copy()
    temp_df.loc[leave_index, "IS_REST"] = True

    span = 1  # 自分自身
    i = leave_index - 1
    while i >= 0 and temp_df.loc[i, "IS_REST"]:
        span += 1
        i -= 1
    i = leave_index + 1
    while i < len(temp_df) and temp_df.loc[i, "IS_REST"]:
        span += 1
        i += 1
    return span

# 各有給候補日について最大連休日数を計算
results = []
for idx in paid_leave_candidates.index:
    span = calc_consecutive_holiday_length(df_year, idx)
    results.append((df_year.loc[idx, "DATE"], span))

results_df = pd.DataFrame(results, columns=["DATE", "HOLIDAY_SPAN"])
max_span = results_df["HOLIDAY_SPAN"].max()
best_dates = results_df[results_df["HOLIDAY_SPAN"] == max_span]

# 結果表示
st.title("有給1日で最大の連休が取れる日")
st.write(f"📆 選択された年: {selected_year}")
st.write(f"💡 有給を1日取得して **{max_span}連休** になる日:")
st.table(best_dates)

# カレンダー描画関数
def draw_calendar(df, highlight_dates, year, month):
    cal = calendar.Calendar()
    days = list(cal.itermonthdays4(year, month))

    df_calendar = pd.DataFrame(columns=["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"])
    week = []
    for day in days:
        y, m, d, wday = day
        if m != month:
            day_str = ""
        else:
            date_obj = pd.Timestamp(year=y, month=m, day=d)
            if date_obj in highlight_dates:
                day_str = f"{d}⭐"
            elif not df[df["DATE"] == date_obj]["IS_REST"].empty and df[df["DATE"] == date_obj]["IS_REST"].values[0]:
                day_str = f"{d}🌿"
            else:
                day_str = str(d)
        week.append(day_str)
        if len(week) == 7:
            df_calendar.loc[len(df_calendar)] = week
            week = []
    if week:
        while len(week) < 7:
            week.append("")
        df_calendar.loc[len(df_calendar)] = week

    st.subheader(f"{year}年 {month}月")
    st.dataframe(df_calendar, use_container_width=True)

# ハイライト対象日抽出
best_dates["DATE"] = pd.to_datetime(best_dates["DATE"])
highlight = best_dates[best_dates["DATE"].dt.year == selected_year]["DATE"].dt.date.tolist()

# カレンダー表示
st.header("📆 カレンダー表示")
months_to_show = sorted(set([d.month for d in best_dates["DATE"] if d.year == selected_year]))

for month in months_to_show:
    y = selected_year
    draw_calendar(df_year, highlight, y, month)

セクションごとにコメントアウトで補足していますが、このスクリプトは、選択した年のカレンダーから、有給を1日取得して最大連休を得られる日を計算し、その結果をカレンダーで表示するものです。
最初に、Snowflakeから祝日や土日情報を取得し、休み判定(祝日または土日)を行って、年ごとのデータを作成します。
次に、ユーザーが年を選択すると、その年のデータに絞り込み、休みでない平日(有給候補)を抽出します。
有給候補を1日休みにして、前後の連休期間を計算する関数を用いて、最大連休日を特定します。
その後、最大連休となる日を表示し、カレンダー上に連休候補日をハイライトします。
最後に、カレンダー描画では月ごとの曜日を表示し、連休候補日を目立たせるために絵文字を使ってマーキングしています。
スクリプトが保存できたら、"setup_scripts.sql"でStreamlitを構築する指示を追加しておきましょう。

CREATE STREAMLIT IF NOT EXISTS core.holidays_streamlit 
FROM '/streamlit' 
MAIN_FILE = '/holidays.py' ;

GRANT USAGE ON STREAMLIT core.holidays_streamlit TO APPLICATION ROLE app_public; 

こちらのクエリをsetup_scripts.sqlファイルの末尾に追加しておきます。
最後に、snowflake.ymlのartifactsセクションに、Streamlitを追加して、デプロイの準備が完了です。

definition_version: 2
entities:
  holidays_pkg:
    type: application package
    stage: stage_content.holidays_stage
    manifest: app/manifest.yml
    distribution: external
    artifacts:
      - src: app/*
        dest: ./
      - src: streamlit/holidays.py
        dest: ./streamlit/
    meta:  
      post_deploy:
      - sql_script: scripts/fetch_data.sql

  holidays_app:
    type: application
    from:
      target: holidays_pkg
    debug: false

4アプリのデプロイ

さて、必要なオブジェクトがすべて揃ったのでいよいよデプロイしていきましょう。
繰り返しになりますが、今回のアプリは外部との共有を前提として作成しているので、バージョンの付与が必須になります。
まずは以下のコマンドをCLIで実行して、アプリパッケージにバージョンを追加します。

snow app version create v1_0 -c internal

前回同様に、コマンドを作り直すか問われるので”y”を入力すると、バージョンが付与されます。
次にこちらのコマンドを実行して、アプリをデプロイしていきましょう。

snow app run --version V1_0 -c internal

アプリが正常にデプロイされると、URLが発行されます。(次のキャプチャは2回目移行のデプロイなので”アップグレード”と表示されています)

発行されたURLにアクセスしてみると、アプリのトップ画面に飛びます。
ロールがACCOUNTADMINになっていることを確認した上で左上のHOLIDAYS_STREMLITをクリックすると、アプリが起動します。
次のキャプチャのようなUIが表示されればデプロイ成功です。

2026年は6連休を作る候補日が4日あることが分かりますね。
このアプリは現段階では有給取得の候補日を調べるだけの非常にシンプルな作りですが、たとえば、使用する有給日数を指定したり、UI上で有給を入れてみて連休がどう変わるか試せる“有給シミュレーター”にしてみるなど、アイディア次第で色々拡張できる可能性があるので是非トライしてみてください。

5アプリの共有

さて、ではいよいよ作成したアプリを共有していきましょう。
共有にはいくつか種類があるのですが、今回は共有先を特定のコンシューマーだけに絞る”プライベートシェアリング”という方法で実装してみたいと思います。
まず、アプリを共有するにはデフォルトのパッチを設定する必要があります。
Snowflake上で、"プロジェクト>アプリパッケージ>HOLIDAYS_PKG"と遷移して、パッチのリリースを設定しましょう。
ここでデフォルトとして設定したパッチが、コンシューマー側にデフォルトでインストールされるパッチとなります。

デフォルトのパッチを設定したら、リストを作成しましょう。
データ>プロバイダーStudioにアクセスして、右上の”リストを作成”をクリックします。
共有方法を問われるので、”指定したコンシューマー”を選択しましょう。

リスト名は任意で設定し、再び”指定したコンシューマーのみ”を選択した状態で次に進みます。
するとリストに入れるオブジェクトを選択する項目が出てくるので、ここで今回作成したアプリパッケージ "holidays_pkg" を選択しましょう。
リストの説明を適宜入力し、コンシューマーのデータ共有アカウントIDを入力します。
データ共有アカウントIDは、ユーザーメニューから”アカウント>アカウントの詳細を表示する>データ共有アカウント識別子”で確認することができます。
識別子が正しくないと、コンシューマー設定ができないのでご注意ください。

ここまでで入力必須の項目は登録完了なので、このリストを公開、つまり共有しましょう。
公開ボタンをクリックすると同時にデータが共有され、次のような画面に切り替わります。

右上に”ライブ”と表示されているのが共有中を意味しています。共有を一時的に停止または中止したい場合は、こちらを”非公開”にすればコンシューマー側からは見えなくなります。
さて、共有されたアプリがコンシューマー側から本当にアクセスできるのか確認してみましょう。
コンシューマー側のSnowsightにACCOUNTADMINとしてログインして、データ製品>アプリにアクセスします。
”最近ユーザーと共有”欄に、先程共有したアプリ(HOLIDAYSアプリ)が表示されているので、こちらを取得していきます。

必要に応じてアプリ名やインストール用のウェアハウスを変更して、取得します。

”インストール済みアプリ”に表示されればインストール完了です。(多少時間がかかることがあります)
アクセスしてみると、プロバイダー側と同じようにアプリのトップ画面が表示されます。
そこでStreamlit HOLIDAYS_APPをクリックしてみると…

プロバイダー側と全く同じUIが表示されました。
このビューは、プロバイダー側に参照元テーブルを保持したままなので、データの更新時にはプロバイダー側のテーブルを更新するだけで、共有先で表示されるデータも更新されます。
いちいちコンシューマー側でなにか更新を行う必要が全く無いので、メンテナンスが非常に楽な構造になっています。

まとめ

今回はネイティブアプリでセキュアビューを使うべきその理由と実際の構築方法について説明してきました。
共有後もプロバイダー側のデータを参照し続けるという若干複雑な構造のため、前回構築したアプリより少し構築に工夫が必要となっています。
ネイティブアプリは共有前提で作成されることが多いと思うのですが、この設定周りの詳細な設定がややこしいので、是非参考にしていただけたら嬉しいです。

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

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

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