0
0

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でアプリケーションを作成したり、SQLウェアハウスを構築したりしてきました。
この記事では、これらを組み合わせて、Databricks Appsで作成したアプリケーションからDatabricks SQLウェアハウスに接続する方法を解説します。

前段

手順

※ コードベースは過去の記事のものを使用しています

  1. 必要なライブラリの追加

    # SQLAlchemyをインストールします。これはPythonのSQLツールキットで、データベースとの対話を容易にします。
    pip install sqlalchemy
    # Alembicをインストールします。これはSQLAlchemyのためのデータベースマイグレーションツールです。
    pip install alembic
    # Databricks専用のSQLAlchemyアダプタをインストールします。
    pip install databricks-sqlalchemy
    # Databricks SQL Connectorをインストールします。これはDatabricksとの効率的なデータベース接続を提供します。
    pip install databricks-sql-connector
    
  2. BackendにCRUD用APIを作成
    例)

    @app.get("/api/items/", response_model=List[ItemResponse])
    def read_items(
        q: Optional[str] = None,
        skip: int = 0,
        limit: int = 100,
        db: Session = Depends(get_db)
    ):
    logger.info(f"Fetching items with query: {q}, skip: {skip}, limit: {limit}")
    
    query = db.query(Item)
    if q:
        query = query.filter(
            or_(
                Item.item_id.ilike(f"%{q}%"),
                Item.query.ilike(f"%{q}%")
                )
            )
        items = query.offset(skip).limit(limit).all()
    return items
    
  3. BackendのDB接続用処理を作成

AlembicのMigrationではカタログとスキーマを指定していましたが、アプリで設定すると接続がうまくいかなかったため、
他の3項目を指定して接続します。

    DATABASE_URL = f"databricks://token:{DATABRICKS_TOKEN}@{DATABRICKS_SERVER_HOSTNAME}?http_path={DATABRICKS_HTTP_PATH}"
    engine = create_engine(DATABASE_URL, connect_args={"verify": False}, echo=True)
    SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

    def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()
  1. app.yamlにDB接続用の環境変数を設定
    環境変数に登録するには、app.yamlのenvに以下のように設定します。

    command: [
      "gunicorn",
      "main:app",
      "-k",
      "uvicorn.workers.UvicornWorker",
      "-w",
      "4",
    ],
    env:
        - DATABRICKS_SERVER_HOSTNAME_PROD 
          <Databricksのホスト名>
        - DATABRICKS_HTTP_PATH_PROD
          <DatabricksのHTTPパス>
        - DATABRICKS_TOKEN_PROD
          <Databricksのアクセストークン>
    
  2. FrontendからBackendのAPIを呼び出す画面を作成
    以下画像のような画面を作成しました
    4_Frontend.png

  3. Frontendのビルド&Backendのstaticフォルダへビルドしたファイルを配置

    # フロントエンドディレクトリに移動
    cd frontend
    # 静的ファイルを生成
    npm run generate
    # 古い静的ファイルをバックエンドディレクトリから削除
    rm -rf ../backend/static
    # 新しく生成した静的ファイルをバックエンドのstaticディレクトリにコピー
    cp -r .output/public ../backend/static
    
  4. Gitコミット&Githubへのデプロイ後、Databricks Appsへデプロイ
    参考:Databricks WorkspaceとGitHubを連携してDatabricks Appsにデプロイする

    git add .
    git commit -m "Databricks Appsへデプロイ"
    git push
    cd ./backend
    databricks apps deploy --app-name <app_name>  --source-code-path /Workspace/Users/<username>/<repo_name>/...
    

つまづきポイント

  • DatabricksのUnity CatalogでCreateIndexを実行すると、The command(s): CreateIndex are not supported in Unity Catalog.が発生
    • マイグレーションファイルでCreateIndexを実行していた
    • Unity Catalogをやめてしまうとマイグレーションの実行に失敗する
    • マイグレーションファイルでIndex作成部分を手動削除することで解決
  • アプリ起動時にsqlalchemy.exc.NoSuchModuleError: Cant load plugin: sqlalchemy.dialects:databricksが発生
    • databricks-sqlalchemyかdatabricks-sql-connectorのあたりがないことが原因
  • Insert文の実行時に、[DELTA_INSERT_COLUMN_MISMATCH] Column id is not specified in INSERTが発生
    • テーブルのidをオートインクリメントの設定にしていた
    • オートインクリメントの設定を削除し、インサートの度にidを指定することで解決
    • UUIDに変更
  • UUIDに変更した後、INVALID_NON_DETERMINISTIC_EXPRESSIONS] The operator expects a deterministic expression, but the actual expression is "columndefinitionが発生
    • IDが非決定性式であることが原因
    • UUIDを文字列として扱うように修正

補足

  • Databricks AppsへのアクセスはDatabricksへの認証済みでないとアクセスできないのか検証
    • シークレットウィンドウで開くと、認証画面が表示される
    • apiを実行するとエラーではなく、空レスポンスが返ってくる
  • ということで、Databricks Appsはアプリ側で認証を実装しなくてもDatabricksの認証機構を使ってアクセス制御ができることがわかった

まとめ

この記事では、Databricks AppsからDatabricks SQLウェアハウスへの接続方法について説明しました。

主なポイントは以下の通りです:

  1. SQLAlchemy、Alembic、Databricks専用のSQLAlchemyアダプタなど、必要なライブラリの導入
  2. バックエンドでのCRUD APIの実装とDB接続処理の設定
  3. app.yamlでの環境変数設定による接続情報の管理
  4. フロントエンドからバックエンドAPIを呼び出す実装

また、実装時の主な課題とその解決方法も記載しました:

  • Unity CatalogでのCreateIndex実行時の制限
  • SQLAlchemy関連の依存関係の問題
  • IDカラムの扱いに関する問題(オートインクリメント、UUID)

参考

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?