Snowflake Arcticと飲食店舗データベース「macci」を組み合わせてみよう

## 飲食店舗データベース「macci」とは

株式会社truestar様と株式会社Review様がとんでもないデータセットの販売を始めました！  

https://prtimes.jp/main/html/rd/p/000000012.000070052.html

しかも無料サンプルまで提供してくれています…ヤバい。

https://x.com/VToshikuni/status/1788394076691370143

## Snowflake Marketplaceで無料サンプルをリクエストする

無料サンプルのリクエストはすごく簡単です。まず、Snowflake Marketplaceを開きます。  

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/b905af25-d9bc-df62-f562-979b586dcca5.png)

データセットを検索します。「macci」「Food Data Japan」などでだいたい出てきます。  

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/0044127b-691e-8a0f-d66f-c636cb8be6d1.png)

「取得」をクリック。  

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/6f20ab1c-b2ed-46dc-77bc-3c5013f2064c.png)

出てきたダイアログでも「取得」をクリック。  

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/5a0114db-02fb-8bb8-1261-444e15a3c350.png)

すぐにデータ共有が行われます。  

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/1af22102-f136-bfeb-92e8-edafddd6f936.png)

もう無料サンプルにクエリを投げられるようになっています！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/f091f53c-3486-e8cd-e0b2-4b21c8ec22eb.png)

## 他のリージョンで無料サンプルを使いたい

SnowflakeはAI/LLMに関する機能が凄まじい勢いでアップデートされています。  
それらの機能は東京リージョンに先駆けてオレゴンリージョンなどでプレビューされることが多いです。  
それらの機能を飲食店舗データベースと組み合わせてみたい…のですが、逆に飲食店舗データベースは国内のみの提供になっているようです。  

なのでどうしても組み合わせたい場合、何らかの方法で他のリージョンにデータをクローンする必要があります。  
今回はクエリしたデータをエクスポートして、他のリージョンでインポートしました。  
自アカウントから自アカウントへのデータのやり取りなので、[利用規約](https://snowflake.re-view.jp/terms)上は明示的には禁止されていないはず…？

https://snowflake.re-view.jp/terms

### 追記(2024/5/10)

自アカウントから自アカウントへのデータのやり取り、問題ないそうです。  
藤さん、ありがとうございます！  

https://x.com/VToshikuni/status/1788710066260218276

## Snowflake Arcticと組み合わせてみる：ワークシート編

データをインポートした後に権限設定するだけですぐに組み合わせることが可能です。  
なお、今回はデータをインポートするときにデータベース名やテーブル名などを変更しています。  

```sql
-- 最初はACCOUNTADMINから始める
USE ROLE ACCOUNTADMIN;

-- インポートしたデータベースに対してアクセスできるようにする
-- FOOD_STORES.PUBLIC.SHIBUYA
-- FOOD_STORES.PUBLIC.OSAKA
-- にそれぞれインポートした
GRANT USAGE ON DATABASE FOOD_STORES TO ROLE cortex_user_role;
GRANT USAGE ON ALL SCHEMAS IN DATABASE FOOD_STORES TO ROLE cortex_user_role;
GRANT USAGE ON FUTURE SCHEMAS IN DATABASE FOOD_STORES TO ROLE cortex_user_role;
GRANT SELECT ON ALL TABLES IN DATABASE FOOD_STORES TO ROLE cortex_user_role;
GRANT SELECT ON FUTURE TABLES IN DATABASE FOOD_STORES TO ROLE cortex_user_role;

-- Snowflake Cortexを呼び出せるロールに切り替える
USE ROLE cortex_user_role;

-- テストクエリを実行
SELECT * FROM FOOD_STORES.PUBLIC.SHIBUYA LIMIT 10;

-- Snowflake Cortexでテーブルの各行に対してLLMを呼び出す
-- https://docs.snowflake.com/en/sql-reference/functions/complete-snowflake-cortex#responses-from-table-column
SELECT
    STORE_NAME,
    SNOWFLAKE.CORTEX.COMPLETE(
        'snowflake-arctic',
        CONCAT('nameタグで囲まれた文字列は飲食店の店名です。この店名が本格イタリアンであると推定されるときは1、そうでなければ0を出力してください。: <name>', STORE_NAME, '</name>')
    ) AS RESPONSE
FROM SHIBUYA LIMIT 500;
```

最後のクエリの結果はこのようになっています。  

![flaged](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/468995ae-efc2-2062-10d7-4bd89953cec3.png)

例えばLLMでデータを加工・分類して自社データと結合する…なんてことができそうです！

## Snowflake Arcticと組み合わせてみる：Python編

もちろんPythonからデータを取得することもできます。  
なので、Pythonで取得したデータを整形して、それをプロンプトに入れ込んで、Snowflake Arcticに何かしてもらう…なんてことも可能です。  

以下のプログラムはユーザが入力したプロンプトにランダムな店名のリストを付記してからSnowflake Arcticに投げる…というものです。  

```py:arctic_with_macci.py
# 環境構築コマンド
# conda create -n arctic python=3.8
# conda activate arctic
# pip install snowflake-connector-python snowflake-snowpark-python snowflake-ml-python[all] streamlit

# 実行コマンド
# streamlit run arctic_st.py

import streamlit as st
import snowflake.connector
import snowflake.snowpark as snowpark
import snowflake.cortex as cortex

# ローカルPython環境からSnowflakeに接続するための関数
@st.cache_resource(ttl=7200)
def connect_snowflake():
    # Snowflakeに接続する
    # 注意！本来はここに指定するパラメータをハードコーディングしてはいけない
    connection = snowflake.connector.connect(
        user='sakatoku',
        password='ここにパスワードを記載',
        account='XXXXXXX-TEST_OREGON (アカウント識別子のドット.をハイフン-に変えたものを記載)',
        role='cortex_user_role',
        warehouse='compute_wh')

    # Snowparkセッションを作成する
    session = snowpark.Session.builder.configs({"connection": connection}).create()
    return session

# 画面レイアウトを設定
st.set_page_config(layout="wide")

# ユーザプロンプトを取得する。ユーザプロンプトが空の場合はここで終了
user_prompt = st.chat_input("Say something")
if not user_prompt:
    st.stop()

# ユーザプロンプトを表示
with st.chat_message("user"):
    st.write(user_prompt)

# Snowflakeに接続する
session = connect_snowflake()

# ユーザプロンプトに結合するデータをSnowflakeから取得する
query = "SELECT STORE_NAME FROM FOOD_STORES.PUBLIC.OSAKA"
knowledge_df = session.sql(query).sample(n=100).collect()
st.dataframe(knowledge_df)

# 取得したデータをユーザプロンプトに結合する
knowledge_text = ""
for row in knowledge_df:
    if len(knowledge_text) > 0:
        knowledge_text += ","
    knowledge_text += row["STORE_NAME"]
user_prompt += f"<STORE_NAME>{knowledge_text}</STORE_NAME>"

# Snowflake Cortex LLM Functionsを呼び出してレスポンスを取得する
# 注意！現在は指定できるのはモデルの種類とプロンプトのみ
# これは指定できない：options = {"temperature": 0.5}
response = cortex.Complete("snowflake-arctic", user_prompt)

# レスポンスを表示
with st.chat_message("arctic"):
    st.write(response)
```

例えばデータを抽出してもらったり。  

![example1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/761b07b1-9ad1-72c7-f515-fc74a12bc8a8.png)

例えばデータをサマリしてもらったり。  

![example2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/accd01fc-2d91-5527-221d-293339e69872.png)

ちなみに、店名のリストを付記している効果があるのかを確認するために、それなしでサマリしてもらうと…

![bad_example](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/9e511cea-2ea9-66fe-a260-42927ff15839.png)

それっぽいことを述べているものの、想像上の美しい大阪のイメージだけで知ったかぶりをしている雰囲気になってしまいます。  
信頼性の高いリアルタイムのデータがLLMにパワーと可能性を与えるんだ！と感じられますね。  

## 余談

プレスリリースを読むと「今後の展開」に…

https://prtimes.jp/main/html/rd/p/000000012.000070052.html

> 「macci」に含まれている飲食店舗以外（医療施設など）のデータベースに関しても、Snowflake Marketplaceにラインナップしていく予定です。

ヤバくない！？

https://macci.re-view.jp/functions.html#func_area1

こんなにすごいデータセットがあるんだぜ…！？