[新機能]SnowflakeのSnowsight上でStreamlitのアプリ開発と実行ができるようになりました #SnowflakeDB

2023.09.19

さがらです。

今朝、SnowflakeのGUI画面であるSnowsight上でStreamlitのアプリ開発と実行ができるようになりました!

簡単にですが早速試してみたので、その内容をまとめてみます。

試してみた

新しくStreamlitというメニューが画面左に追加されています。

Streamlitメニューを押すと、画面右に下図のような画面が出てきます。

「早速アプリ作るぞ~!」となりますが、事前にアプリケーションを保持する場所として必要なデータベース・スキーマの準備、使用するウェアハウス、開発を行うロールの作成と権限付与、が必要となります。

一番上のHere is an example script.を押してみると、この準備のためのSQLが書かれたワークシートが開きます。 ※このHere is an example script.が書かれた注意書きですが、私が検証したときにはACCOUNTADMINロールを使用しているときしか出てきませんでした。

実際に私はこのスクリプトを少し変更し、下記の内容で実行しました。

変数定義だけ行えば任意の名称でオブジェクトを作成するように記述しています。※おまけでSYSADMINの子ロールにするようにしています。

begin;
    -- 必要な変数定義 ※各変数の名称は変更してください
    set database_name = 'DB_NAME';
    set schema_name = 'DB_NAME.SCHEMA_NAME';
    set warehouse_name = 'WH_NAME';
    set role_name = 'ROLE_NAME';

    -- SYSADMINでデータベース・スキーマ・ウェアハウスの作成
    use role sysadmin;
    create database if not exists identifier($database_name);
    use database identifier($database_name);
    create schema if not exists identifier($schema_name);

    create warehouse if not exists identifier($warehouse_name)
       warehouse_size = xsmall
       warehouse_type = standard
       auto_suspend = 60
       auto_resume = true
       initially_suspended = true;

    -- Stremalit用のロールを作成
    use role securityadmin;
    create role if not exists identifier($role_name);
    
    -- 作成したロールに、各権限を付与
    use role sysadmin;
    grant usage on database identifier($database_name) to role identifier($role_name);
    grant usage on schema identifier($schema_name) to role identifier($role_name);
    grant create streamlit on schema identifier($schema_name) to role identifier($role_name);
    grant create stage on schema identifier($schema_name) to role identifier($role_name);

    grant usage on warehouse identifier($warehouse_name) to role identifier($role_name);

    -- 作成したロールを、SYSADMINの子ロールにする
    use role securityadmin;
    grant role identifier($role_name) to role sysadmin;

commit;

準備が出来たら、SnowsightのStreamlitメニューに戻り、右上の+ Streamlit Appを押します。

するとポップアップが立ち上がるので、App nameに任意の名前を入れて、WarehouseApp locationは先程準備をしたものを使用します。

すると、デフォルトで記述されているStreamlitのコードが自動で実行され、下図のようにExample Streamlit Appが表示されると思います!基本的には、画面左のエディターでコードを記述し、右側でアプリが実行されるというUIです。

また、右上のShareを押すと、ワークシートやダッシュボードと同じように他のロールに権限を付与することも可能です。

(以下、2023/9/20追記)

Packageが追加で必要になることもあると思いますが、エディター欄の一番上のPackagesを押すと、現在インストール済のPackages一覧が出てきます。

新しいPackagesのインストールが必要な場合は、検索欄で任意のPackageの名称を入力し、対象のPackageを押せばインストール出来ます!

インストールしたPackageのバージョンを切り替えたい場合は、リストから選択すればOKです。

おまけ:Snowflake上のデータを参照するアプリを動かしてみた

上述のサンプルアプリは、コード内でDataFrameを直接定義しているため、Snowflake上のテーブルは参照していません。

そのためおまけとして、Snowflake上のテーブルを参照するアプリケーションを動かしてみたいと思います。

使用するのは、Quickstartの「Getting Started With Snowpark for Python and Streamlit」です。 注意点として、このQuickstartで使用しているデータはAWSのUS West (Oregon)リージョンでホストしているSnowflakeアカウントでしか取得できないため、ご注意ください。

やってみた

まず、Marketplaceの「Environment Data Atlas」のデータを取得し、Streamlitのアプリを開発するロールに権限付与しておきます。

※上述の通り、AWSのUS West (Oregon)リージョンでホストしているSnowflakeアカウントでのみこのデータを取得可能のため、ご注意ください。

この上で、Streamlitメニューから新しくアプリを作成します。

あとは、このQuickstartに記述されているコードをコピーして貼り付け、右上のRunを押せば、Marketplaceで取得したKnoemaのデータを参照するアプリケーションが動きます!

このコードではSnowflake上のテーブルをDataFrameとして取得する処理なども記述されているため、参考になるところも多いと思います。

2023年9月19日時点のQuickstart上のStreamlitのコード
# Import libraries
from snowflake.snowpark.context import get_active_session
from snowflake.snowpark.functions import sum, col
import altair as alt
import streamlit as st

# Set page config
st.set_page_config(layout="wide")

# Get current session
session = get_active_session()

@st.cache_data()
def load_data():
    # Load CO2 emissions data
    snow_df_co2 = session.table("ENVIRONMENT_DATA_ATLAS.ENVIRONMENT.EDGARED2019").filter(col('Indicator Name') == 'Fossil CO2 Emissions').filter(col('Type Name') == 'All Type').sort('"Date"').with_column_renamed('"Date"','"Year"')

    # Load forest occupied land area data
    snow_df_land = session.table("ENVIRONMENT_DATA_ATLAS.ENVIRONMENT.\"WBWDI2019Jan\"").filter(col('Series Name') == 'Forest area (% of land area)')
    snow_df_land = snow_df_land.group_by('Country Name').agg(sum('$61').alias("Total Share of Forest Land")).sort('Country Name')
    return snow_df_co2.to_pandas(), snow_df_land.to_pandas()

# Load and cache data
df_co2_overtime, df_forest_land = load_data()

def co2_emmissions():
    st.subheader('CO2 Emissions by Countries Over Time')

    countries = ['United States','China','Russia','India','United Kingdom','Germany','Japan','Canada']
    selected_countries = st.multiselect('',countries, default = ['United States','China','Russia','India','United Kingdom'])
    st.markdown("___")

    # Display an interactive chart to visualize CO2 emissions over time for the selected countries
    with st.container():
        countries_list = countries if len(selected_countries) == 0 else selected_countries
        df_co2_overtime_filtered = df_co2_overtime[df_co2_overtime['Location Name'].isin(countries_list)]
        line_chart = alt.Chart(df_co2_overtime_filtered).mark_line(
            color="lightblue",
            line=True,
            point=alt.OverlayMarkDef(color="red")
        ).encode(
            x='Year',
            y='Value',
            color='Location Name',
            tooltip=['Location Name','Year','Value']
        )
        st.altair_chart(line_chart, use_container_width=True)

def forest_occupied_land():
    st.subheader('Forest Occupied Land Area by Countries')

    threshold = st.slider(label='Forest Occupied Land By Countries', min_value=1000, max_value=2500, value=1800, step=200, label_visibility='hidden')
    st.markdown("___")

    # Display an interactive chart to visualize forest occupied land area by countries
    with st.container():
        filter = df_forest_land['Total Share of Forest Land'] > threshold
        pd_df_land_top_n = df_forest_land.where(filter)
        st.bar_chart(data=pd_df_land_top_n.set_index('Country Name'), width=850, height=400, use_container_width=True) 

# Display header
st.header("Knoema: Environment Data Atlas")

# Create sidebar and load the first page
page_names_to_funcs = {
    "CO2 Emissions": co2_emmissions,
    "Forest Occupied Land": forest_occupied_land
}
selected_page = st.sidebar.selectbox("Select", page_names_to_funcs.keys())
page_names_to_funcs[selected_page]()

最後に

SnowflakeのGUI画面であるSnowsight上でStreamlitのアプリ開発と実行ができるようになったので、簡単ですが試してみました。

ローカルで開発環境を用意せずとも、Snowflake上で簡単にStreamlitのコードを記述して実行できるのは本当に便利ですよね!

Streamlitの学習には30 Days of Streamlitなども参考にしてみてください。