3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Databricks AppsでVolumeを読み書きする際に注意すること

3
Last updated at Posted at 2025-12-03

テーブルの読み書きはやったことがあったのですが、よく考えたらボリュームの読み書きの実装をしたことがありませんでした。

ノートブックで読み書きするノリでやるとハマるので注意点をまとめます。私が遭遇したエラーは:

FileNotFoundError: [Errno 2] No such file or directory: '/Volumes/workspace/de_handson/data_files'

Screenshot 2025-12-03 at 6.43.25.png

もちろん、ボリュームのパスは存在しています。

注意点

  1. アプリからボリュームにアクセスする際には、ボリュームのパス/Volumes/...に直接アクセスするのではなく、Databricks SDKを経由する
  2. アプリのサービスプリンシパルにボリュームのアクセス権を付与する

特に1点目に注意です。ノートブックの場合、/Volumes/...のパスで直接読み書きできますが、Appの動作しているコンテナ環境にはUnity Catalogボリュームがマウントされていないので、ノートブックのノリで pd.read_csv("/Volumes/...")などとやると冒頭のエラーになります。

こちらのクックブックに説明があります。

Unlike notebooks, Databricks Apps does not support mounting Unity Catalog volumes and directly reading and writing files. As this code snippet demonstrates, each file needs to be downloaded to the app compute before being able to manipulate it.

ノートブックとは異なり、Databricks AppsではUnity Catalogボリュームのマウントや、ファイルの直接の読み書きはサポートしていません。このコードスニペットで示しているように、それぞれのファイルは操作する前にアプリのコンピュートにダウンロードする必要があります。

こちらのコミュニティのやり取りでも言及されています。

2点目のアクセス権はアプリのリソースとしてボリュームを追加することで自動で設定されます。手動で設定しても構いませんが、わかりやすさの観点でもリソースとして設定することをお勧めします。

実践

カスタムアプリを作成します。
Screenshot 2025-12-03 at 9.52.45.png

名前と説明文。
Screenshot 2025-12-03 at 9.53.41.png

リソースを追加をクリック。
Screenshot 2025-12-03 at 9.53.50.png

UCボリュームを選択。
Screenshot 2025-12-03 at 9.53.58.png

ボリュームのパスを選択し、権限には読み取りと書き込みを指定。
Screenshot 2025-12-03 at 9.54.30.png

これで、アクセスするボリュームにアプリのサービスプリンシパルの権限が設定されます。これで、権限の問題はクリアしましたが、マウントポイントの問題が残っています。
Screenshot 2025-12-03 at 9.54.41.png

まず、app.yamlではstreamlitが動くようにしておき、リソースで定義したボリュームパスを環境変数で参照できるようにしておきます。requirements.txtは依存関係がなければ空で大丈夫です。

app.yaml
command: [
  "streamlit", 
  "run",
  "app.py"
]

env:
  - name: VOLUME_PATH
    valueFrom: volume

そして、マウントポイントの問題を回避するために、app.pyで以下のように実装します。ここでのポイントは、アプリから直接ボリュームパスを参照するのではなく、Databricks SDKでファイルをアプリが動いているコンピュートのローカルにダウンロードしてからアクセスしているという点です。w.files...などと記載されている部分でSDKを使っています。

app.py
import os
import streamlit as st
import pandas as pd
import plotly.express as px
from databricks.sdk import WorkspaceClient

st.set_page_config(layout="wide")

# Unity Catalogボリュームのパスを指定(例: /Volumes/my_catalog/my_schema/my_volume)
# app.yaml経由で渡される環境変数を参照
VOLUME_PATH = os.getenv("VOLUME_PATH")

# WorkspaceClientの初期化
w = WorkspaceClient()

# ボリューム内のCSVファイル一覧を取得
def list_csv_files_in_volume():
    files = w.files.list_directory_contents(VOLUME_PATH)
    csv_files = [f.path for f in files if f.path.endswith('.csv')]
    return csv_files

# Volumeからファイルをダウンロードしてローカルパスを返す
# https://apps-cookbook.dev/docs/streamlit/volumes/volumes_download/
def download_csv_file(volume_path: str) -> str:
    # files.download() を使う(workspace.download() ではない)
    response = w.files.download(volume_path)
    file_content = response.contents.read()
    
    # ローカルに保存
    local_path = f"/tmp/{os.path.basename(volume_path)}"
    with open(local_path, 'wb') as f:
        f.write(file_content)
    
    return local_path

# ローカルパスからCSVをロード
def load_csv(local_path):
    return pd.read_csv(local_path)

st.header("Unity CatalogボリュームのCSVファイル可視化")

# ファイルアップロード機能
uploaded_file = st.file_uploader("CSVファイルをアップロード", type=["csv"])
if uploaded_file is not None:
    # ボリュームへのアップロード
    save_path = os.path.join(VOLUME_PATH, uploaded_file.name)
    w.files.upload(
        save_path,
        uploaded_file
    )
    st.success(f"{uploaded_file.name} をアップロードしました。")
    # ファイルポインタを先頭に戻す
    uploaded_file.seek(0)
    # アップロード直後に内容表示
    df_uploaded = pd.read_csv(uploaded_file)
    st.subheader("アップロードしたファイルの内容")
    st.dataframe(df_uploaded, height=400, use_container_width=True)

csv_files = list_csv_files_in_volume()
selected_file = st.selectbox("CSVファイルを選択してください", csv_files)

if selected_file:
    local_path = download_csv_file(selected_file)
    data = load_csv(local_path)
    st.dataframe(data, height=600, use_container_width=True)
    st.subheader("Plotlyで可視化")
    columns = data.columns.tolist()
    x_col = st.selectbox("X軸", columns)
    y_col = st.selectbox("Y軸", columns)
    fig = px.scatter(data, x=x_col, y=y_col, height=400, width=700)
    st.plotly_chart(fig, use_container_width=True)

アプリにアクセスすると以下のような画面になります。
Screenshot 2025-12-03 at 10.34.36.png

ファイルをアップロードします。
Screenshot 2025-12-03 at 10.35.23.png

ボリュームにもアップロードされています。
Screenshot 2025-12-03 at 10.35.42.png

ボリューム内のファイルを選択して表示することもできます。
Screenshot 2025-12-03 at 10.36.34.png

簡単な可視化もできます。
Screenshot 2025-12-03 at 10.37.10.png

はじめてのDatabricks

はじめてのDatabricks

Databricks無料トライアル

Databricks無料トライアル

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?