databricks-serverless-migration について
databricks-serverless-migration は、Databricks のワークロードを分析し、クラシックコンピュートからサーバーレスコンピュートへの移行を支援するエージェントスキルです。互換性の分析、テスト、検証を段階的に進め、コードや設定の修正案を示します。
主な機能
- 01クラシックコンピュートのワークロード分析
- 02サーバーレス互換性の問題検出
- 03コードと設定の修正案提示
- 04複数ノートブックの段階的な移行
- 05テスト比較と移行の検証
活用シーン
- 01ノートブック、ジョブ、パイプラインの移行
- 02既存コードのサーバーレス互換性確認
- 03サーバーレス向けコードの作成
- 04移行後に発生した固有エラーの調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ databricks/ databricks-agent-skills --skill databricks-serverless-migrationインストール後、Claude Code で/databricks-serverless-migrationを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
agents/openai.yamlassets/databricks.svgreferences/code-patterns.mdcompatibility-checks.mdconfiguration-guide.mdfailure-reporting.mdinstall-in-databricks-genie-code.mdjar-migration.mdmlflow-uc-patterns.mdmulti-source-enumeration.mdnetworking-and-security.mdstreaming-migration.md詳細
Serverless Compute の移行
最初に:CLI の基本、認証、プロファイルの選択については、親の databricks-core スキルを使用してください。
既存の Databricks コードが serverless compute と互換性があるか分析し、classic クラスターからの移行をガイドします。このスキルでは、取り込み → 互換性の分析 → A/B 比較によるテスト → 検証と反復、という4段階の移行ライフサイクルに従います。
このスキルを使用する場面
- ノートブック、ジョブ、パイプラインを classic compute から serverless に移行する場合
- 既存のコードが serverless と互換性があるか確認する場合
- serverless compute を対象とする新しいコードを作成する場合
- 移行後に serverless 固有のエラーをトラブルシューティングする場合
- Performance-Optimized モードと Standard モードのどちらを選ぶか検討する場合
このスキルの実行場所
このスキルは Agent Skill(agentskills.io)として公開されており、互換性のある任意のクライアントで実行できます。
- ノート PC 上の Claude Code、Cursor、または任意の agentskills.io クライアント — デフォルトの実行場所です。
databricks aitools installでインストールするか、クライアントごとのドキュメントに従ってください。 - Genie Code Agent モードを使って Databricks ワークスペース内で実行する場合 — このスキルを
/Workspace/Users/<you>/.assistant/skills/databricks-serverless-migration/(ユーザーごと)または/Workspace/.assistant/skills/databricks-serverless-migration/(ワークスペース全体、管理者のみ)に配置してください。3つのインストール方法と、serverless compute に関する重要な注意事項(serverless には Databricks CLI がプリインストールされていないため、一部のデプロイ手順の調整が必要です)については、Databricks Genie Code へのインストールを参照してください。
ノート PC のクライアントから現在実行しているユーザーの移行分析を完了した場合は、最後に Genie Code の選択肢を一度案内してください。ワークロードがあるワークスペース内で移行を反復することを好むユーザーは少なくありません。
移行を妨げる要因について
移行を妨げる要因は、次の3つのカテゴリに分かれます。カテゴリ2に注力してください。このスキルが最も役立つのはこのカテゴリです。
| カテゴリ | 説明 | 対応 |
|---|---|---|
| 1. 機能拡張中 | Databricks が現在サポートを拡張中です(例:SparkML、カスタム JDBC) | 今は回避策を使い、後で再確認してください |
| 2. コード/設定の変更が必要 | コードで serverless 向けに更新が必要なパターンを使用しています(例:RDD、DBFS、ストリーミングトリガー) | このスキルが役立ちます — これらのパターンを検出し、修正方法を提示します |
| 3. classic 専用 | ワークロードで serverless では利用できない機能が必要です(例:OS の root アクセス、R 言語) | classic compute を使い続けてください |
判断フロー:ワークロードの準備はできていますか?
Workload → Check language
├── R code → Category 3: keep on classic
├── Scala notebook cells → Category 2: port to PySpark/SQL, or compile as a JAR job task
├── Compiled Scala JAR (spark_jar_task, build.sbt/pom.xml/build.gradle) → see references/jar-migration.md
│ ├── Scala 2.12 build? → recompile against 2.13.16
│ ├── Bundles spark-core/spark-sql? → use databricks-connect % Provided
│ └── Bundles libs on the kernel classpath? → mark % Provided (see the classpath table in references/jar-migration.md)
├── Python / SQL → Continue
├── Uses RDD APIs? → Category 2: rewrite to DataFrame API (see fixes below)
├── Uses DBFS paths? → Category 2: migrate to UC Volumes
├── Uses Hive Metastore? → Category 2: migrate to Unity Catalog (or use HMS Federation)
├── Uses df.cache/persist? → Category 1: remove and materialize to Delta (native support coming soon)
├── Uses streaming?
│ ├── ProcessingTime trigger → Category 2: use AvailableNow or migrate to SDP
│ ├── Continuous trigger → Category 2: use SDP continuous mode
│ ├── No trigger specified → Category 2: add explicit .trigger(availableNow=True)
│ └── AvailableNow / Once → Ready ✓
├── Uses init scripts? → Category 2: use Environments
├── Uses VPC peering? → Category 2: use NCCs / Private Link
├── Uses unsupported Spark configs? → Category 2: remove (serverless auto-tunes)
├── Uses custom JDBC drivers? → Category 2: use Lakehouse Federation or built-in JDBC
├── Uses Docker containers? → Category 3: use Environments for libs, or keep on classic
└── All clear → Ready for serverless ✓
移行ワークフロー
ステップ 1:取り込み — ワークロードのコンテキストを収集する
移行先が serverless compute であることを確認してください。 このスキルは classic → serverless の移行に特化して設計されています。チェック、修正、ワークフローはすべて、serverless compute アーキテクチャ(Spark Connect、Environments、NCC)を対象としています。ユーザーが classic DBR バージョン間のアップグレードを希望している場合、このスキルは適用されません。classic DBR のアップグレードでは互換性の対象範囲が異なるため、標準の DBR アップグレードガイドに従ってください。
serverless に移行する対象の全体像を把握してください。
- ユーザーのノートブック/スクリプトファイルを読み取ります
- classic クラスターの構成(インスタンスタイプ、DBR バージョン、Spark 設定、初期化スクリプト、ライブラリ)を特定します
- ネットワーク構成(VPC ピアリング、インスタンスプロファイル、マウント)を確認します
- ワークロードの種類(バッチジョブ、ストリーミング、インタラクティブノートブック、パイプライン)を把握します
- 移行先を特定します。出力は常に serverless compute の構成であり、新しい DBR を使用する classic クラスターではありません
Step 1.5: 複数のノートブックにまたがるワークロードへの対応
ワークロードが複数のユーザーノートブックにまたがる場合(_resources/ のセットアップ用ノートブックは数に含めません)、一度にすべて処理するのではなく、1つずつ処理してください。エージェントのコンテキストウィンドウには上限があります。分析、修正、移行を行いながら、8つのノートブックからなるジョブのソース全体をアクティブなコンテキストに保持しようとすると、コンテキストの自動圧縮が繰り返し発生します(Claude Code)。ほかのクライアントでも、同様のコンテキストあふれによる障害が起こります。
手順:
- まず列挙します。 すべてのユーザーノートブックをパスとともに一覧表示します。全体像を把握するための数行を除き、まだ本文をすべて読まないでください。
bundle_config.py(H4)の有無を確認します。 ソースツリーにbundle_config.pyがある場合は、内容を解析し、上流ソースに関する宣言(git URL、S3 パス、init_scripts、git_source、またはカスタムの上流リポジトリ宣言)に従ってください。参照されている各リポジトリを兄弟ディレクトリにクローンまたはフェッチし、そのノートブックを一覧に含めます。移行計画では「外部ソース」を独立した成果物カテゴリーとして一覧表示します。この手順を行わないと、複数のソースを参照するデモ(例:dbt-on-databricksは上流のdbt-databricks-c360リポジトリを参照します)の列挙が不正確になり、実際のタスク用ノートブックが見落とされます。
- 各ノートブックについて、順番に次を行います。
a. ソース全体を読みます。
b. このノートブックだけを対象に、Step 2 の Analyze チェックリストを実行します。
c. 構造化された要約を回答または一時ファイルに記録してから、元のソースをアクティブな作業メモリから削除します。要約には次の項目を含めます。
notebook_path(相対パス)detected_patterns[](このスキルのカタログにあるパターン ID)blockers[](このノートブックに該当する Category-3 のパターンがあれば記載)migration_steps[](順序付けした具体的な修正手順)unmigratable(bool — 回避策のない blocker が1つでもある場合は true) d. 書き込み可能な一時ディレクトリ(~/.databricks-migration-skill/scratch/<run-id>/findings/)がある場合は、要約を<notebook-basename>.jsonとして保存します。これにより、ソースをコンテキストから安全に解放できます。ない場合は、会話履歴内に要約を簡潔に保管します。
- 統合します。 すべてのノートブックの要約が揃ったら、要約だけをもとに統合移行計画を作成します。修正はノートブックごとに適用し、要約の曖昧さを解消する必要がある場合を除き、元のソースを読み直さないでください。
- 障害の報告。 Failure Reporting Protocol は、ノートブックごとではなく、ワークロードごとに正確に1回実行します。レポートの
detected_patterns配列には全ノートブックの内容を集約します。notebook_characteristicsには、行数の合計と、言語、ストリーミング、ML の各フラグの和集合を使用します。
しきい値の目安:ユーザーノートブックが3つ以上の場合、または個々のノートブックのソースが約5KBを超える場合は、この手順を適用してください。小規模なノートブックが1〜2個の場合は、Step 2〜4 のシングルパスのワークフローで問題ありません。
アンチパターン:「すべてのノートブックを1つの大きなファイルに結合する」戦略や、「すべてのノートブックを読んでから、1回の巨大なターンで作業する」戦略を試さないでください。どちらも、元のコンテキスト圧迫の問題を再び引き起こし、目的に反します。
ステップ 2:分析 — サーバーレス対応状況を確認する
ノートブックは実行前に読み、失敗したジョブの実行結果から問題を見つけようとしないでください。 事前のスキャンを行えば、エラートレースを見ながら試行錯誤するよりも早く非互換性を発見できます。また、サーバーレスでの失敗の多く(ハードコードされたカタログ参照、init スクリプト、依存関係の不足)は静的解析で簡単に見つけられますが、実行失敗後のデバッグには多大な時間がかかります。
テストジョブを作成または実行する前に、次の作業を行ってください。
- ジョブから参照されるすべてのノートブックとソースファイルを読む
- ハードコードされたカタログ/スキーマ参照をすべてスキャンする(例:
spark.table("main.schema.table")、spark.sql("... FROM main...")、catalog = "main") - 依存関係のパターンを確認する:init スクリプト、ローカルの wheel ファイル、カスタムインストール関数、
%pip installの行 requirements.txtまたは同等のファイルを特定し、依存関係一式を解決する- OS レベルのインストール(
apt install、yum install)を、変換またはエスカレーションの対象として報告する
サーバーレスコンピュートのアーキテクチャと互換性のないパターンがないか、コードをスキャンしてください。これらの確認項目はサーバーレス固有のものです。ほとんどのパターンは、DBR のバージョンにかかわらず、クラシックコンピュートでは問題なく動作します。見つかった問題ごとに、次の内容を報告してください。
- カテゴリ:該当する 3 つのブロッカーのカテゴリ
- 重大度:ブロッカー(サーバーレスで必ず修正)/警告(修正を推奨)/情報(認識しておくべき事項)
- パターン:検出された内容と場所
- 修正方法:サーバーレスコンピュートを対象とした具体的な修正方法
書き換え後のリント:セルマジック境界の確認(A1)
影響大。 移行済みのノートブックを使用可能と判断する前に、すべての出力セルに対してこのリントを実行してください。dbdemos E2E スイープで、3/7 のデモが失敗した原因となりました(hls-readmission、fsi-fraud、retail-c360)。
検出方法:# MAGIC %<word> の行(例:# MAGIC %run、# MAGIC %sql、# MAGIC %md、# MAGIC %pip、# MAGIC %fs)を含むセルを特定します。そのセル内の空でないすべての行は、# MAGIC で始まるか、空行でなければなりません。同じセル内で、プレーンな Python コメント(またはその他の Python コード)が # MAGIC %... ディレクティブより前にある場合、そのセルは破損しています。Databricks はそのセルを Python として解析し、%run は IPython の行マジックとして処理されるため、File './00-global-setup-v2' not found のようなエラーが発生します。
修正方法:同じセル内で、プレーンな Python コメントを # MAGIC %... の行より前に追加しないでください。有効な方法は次の 2 つです。
- 推奨:移行に関するメモを、その上にある独立した
# MAGIC %mdセル(専用の# COMMAND ----------ブロック)に記載する。 - 許容:移行に関するメモを完全に削除し、git/ファイルの履歴に委ねる。
修正前の例(破損状態。%run は File not found で失敗します):
# COMMAND ----------
# Migration: relative '%run ../../../_resources/00-global-setup-v2' may not
# resolve under serverless job tasks. Replaced with sibling reference.
# MAGIC %run ./00-global-setup-v2
修正後の例(問題なし。%run はセルマジックとして実行されます):
# COMMAND ----------
# MAGIC %md
# MAGIC Migration: relative %run path replaced with sibling reference.
# COMMAND ----------
# MAGIC %run ./00-global-setup-v2
カテゴリ A:非対応 API
| パターン | 重大度 | 修正 |
|---|---|---|
sc.parallelize(data) | ブロッカー | spark.createDataFrame([(x,) for x in data], ["value"]) |
rdd.map(fn) | ブロッカー | df.select(F.col("value") * 2) または df.withColumn(...) |
rdd.filter(fn) | ブロッカー | df.filter(F.col("value") > 3) |
rdd.reduce(fn) | ブロッカー | df.agg(F.sum("col")).collect()[0][0] |
rdd.flatMap(fn) | ブロッカー | df.select(F.explode(F.split(col, " "))) |
rdd.groupByKey() | ブロッカー | df.groupBy("key").agg(F.collect_list("value")) |
rdd.mapPartitions(fn) | ブロッカー | df.groupBy(F.spark_partition_id()).applyInPandas(fn, schema) |
sc.textFile(path) | ブロッカー | spark.read.text(path) |
sc.wholeTextFiles(path) | ブロッカー | spark.read.format("binaryFile").load(path) |
sc.broadcast(data) | ブロッカー | from pyspark.sql.functions import broadcast; df.join(broadcast(lookup_df), key) |
sc.accumulator(init) | ブロッカー | df.agg(F.sum("col")) または df.count() |
spark.sparkContext | ブロッカー | spark(SparkSession)を直接使用します |
SparkContext.getOrCreate() | ブロッカー | サポートされていません — RuntimeError: Only remote Spark sessions using Databricks Connect are supported が発生します。データのセットアップには spark.createDataFrame() または spark.range() に置き換えてください。 |
sqlContext.sql(query) | ブロッカー | spark.sql(query) |
sc.hadoopConfiguration.set(...) | ブロッカー | UC 外部ロケーションを使用します — 認証情報の設定は不要です |
df.cache() / df.persist() | 警告 | キャッシュ呼び出しを削除します。コストの高い中間結果は Delta テーブルに実体化してください。ネイティブサポートは近日提供予定です。 |
df.checkpoint() | 警告 | 代わりに Delta テーブルに書き込みます |
spark.catalog.cacheTable(t) / CACHE TABLE | 警告 | 削除します — サーバーレスでは不要です |
ノートブックの %scala セル | ブロッカー | PySpark/SQL に移植するか、ジョブタスク用の JAR としてコンパイルします |
ノートブックの %r セル | ブロッカー | サーバーレスには同等の機能がありません — クラシック環境に残すか、PySpark に移植します |
Hive 変数構文 ${var} | 警告 | DECLARE VARIABLE / SET VARIABLE(SQL)または Python の f 文字列を使用します |
CREATE GLOBAL TEMPORARY VIEW | ブロッカー | CREATE OR REPLACE TEMPORARY VIEW を使用します — サーバーレスには global_temp データベースがありません |
クエリ内の global_temp. プレフィックス | 警告 | プレフィックスを削除します — セッションスコープの一時ビューは修飾子なしでアクセスできます |
from pyspark.sql.functions import *(A2)を使った組み込みの max(..., key=) / min(..., key=) / sorted(..., key=) | ブロッカー | pyspark.sql.functions.max が組み込み関数をシャドーイングし、key= を受け付けません(TypeError: max() got an unexpected keyword argument 'key' が発生します)。sort+index を使用します:xs.sort(key=...); top = xs[0]。MLflow on UC を参照してください。 |
from databricks import automl / automl.classify() / automl.regress() / automl.forecast()(A3) | ブロッカー | AutoML はサーバーレスでは利用できず、DBDemos.create_mockup_automl_run のフォールバックは Spark Connect で PlanMetrics not JSON serializable エラーを引き起こします。インラインの scikit-learn Pipeline に書き換え、mlflow.sklearn.log_model + mlflow.register_model + UC エイリアスを使用してください。MLflow on UC を参照してください。 |
mlflow.pyfunc.spark_udf(...) に続く df.withColumn("prediction", loaded_model(struct(*features)))(A4) | mlflow 2.19.0 ではブロッカー | Spark Connect のクロージャーのバグ:batch_predict_fn が loaded_model を自由変数としてキャプチャし、ワーカーで NameError: cannot access free variable 'loaded_model' が発生します。根本原因は Spark Connect のシリアライズです。 推奨の修正(移植性があり、任意の mlflow で動作):ドライバー側で pandas 推論を行います:mlflow.pyfunc.load_model(uri).predict(df.toPandas()) の後に spark.createDataFrame(...) を呼び出します。代替の修正:環境仕様で mlflow>=2.20.0 を固定します。 |
モデルサービングエンドポイントの作成における AutoCaptureConfigInput(enabled=...)(A5) | 警告 | 非推奨の引数で、初回のエンドポイントデプロイを妨げます。EndpointCoreConfigInput(...) から auto_capture_config=AutoCaptureConfigInput(...) パラメーターを完全に削除します。 |
mlflow.set_registry_uri("databricks-uc") が有効なスコープ内での mlflow.<flavor>.log_model(..., registered_model_name=...)(M1) | ブロッカー | UC では registered_model_name= によって内部で get_model_version_by_alias(..., 'Champion') が呼び出され、新規モデルの場合は RESOURCE_DOES_NOT_EXIST が発生します。log_model からこのキーワード引数を削除し、実行後に mlflow.register_model(model_uri=f"runs:/{run.info.run_id}/model", name=<full_name>) と MlflowClient().set_registered_model_alias(...) を呼び出します。MLflow on UC を参照してください。 |
UC に登録されたモデルでの .latest_versions へのアクセス(例:client.get_registered_model(name).latest_versions)(M2) | ブロッカー | UC では RegisteredModel.latest_versions は常に None です。max(None, key=...) は TypeError: 'NoneType' object is not iterable を発生させます。client.search_model_versions(f"name='{name}'") と sort+index を使用します(上記 A2 を参照)。MLflow on UC を参照してください。 |
mlflow.set_registry_uri("databricks-uc") が有効なスコープ内での、signature= キーワード引数なしの mlflow.<flavor>.log_model(...)(M3) | ブロッカー | UC では、登録するすべてのモデルにモデルシグネチャが必要です。signature= がない場合、log_model は MlflowException: Model signature is required for registering a model to Unity Catalog を発生させます。サンプルから推論します:signature = infer_signature(X_sample, model.predict(X_sample)) を実行し、log_model に signature=signature として渡します。MLflow on UC を参照してください。 |
後続の Delta テーブルで Integer が期待される場合に、二値分類器の予測列が float64(Double)として書き込まれる(M4) | 初回書き込み時のブロッカー | sklearn の二値分類器(例:A3 の AutoML から sklearn への書き換え)は、predict() の結果を float64 として出力します。prediction 列が IntegerType の Delta テーブルに書き込むと、DELTA_FAILED_TO_MERGE_FIELDS: prediction (Double) vs prediction (Integer) が発生します。書き込み前にキャストします:df.withColumn("prediction", col("prediction").cast("integer"))。MLflow on UC を参照してください。 |
| カテゴリ B:データアクセス |
| パターン | 重大度 | 修正方法 |
|---|---|---|
dbfs:/ or /dbfs/ paths (persistent data) | ブロッカー | /Volumes/<your_catalog>/schema/volume/path に置き換えます |
dbfs:/tmp/, /dbfs/tmp/, paths with cache/scratch/temp | 警告 | /tmp/ または /local_disk0/tmp/(ローカルドライバーディスク)を使用します。パフォーマンス上の理由から、一時ファイルには Volumes を使用しないでください |
file:///dbfs/ FUSE mount paths | 警告 | 永続パスは /Volumes/... に、一時パスは /local_disk0/tmp/ に置き換えます |
dbutils.fs.mount(...) | ブロッカー | UC 外部ロケーションと外部ボリュームを作成します |
hive_metastore.db.table | 警告 | UC に移行するか、HMS Federation を使用します:CREATE FOREIGN CATALOG ... USING CONNECTION hms_connection |
USE CATALOG または 3 階層名を指定せずに実行する CREATE DATABASE/CREATE SCHEMA | ブロッカー | CREATE 文の前に、ノートブックの先頭で spark.sql("USE CATALOG <your_catalog>") を追加します。既存のテーブル参照から対象カタログを特定するか、ユーザーに確認します。 |
| IAM instance profile references | 警告 | UC 外部ロケーションとストレージ認証情報を使用します |
| Hive SerDe tables | ブロッカー | UC の Delta テーブルに移行します |
config.py、config/__init__.py、_config*.py、または %run で参照される Python ファイル内の単独の catalog = "<value>" / schema = "<value>" 代入(B1) | ブロッカー | カタログの書き換えでは、spark.table(...) を含むノートブック本体だけでなく、すべての設定ファイルをスキャンする必要があります。"main"、"main__build"、"hive_metastore" などのリテラルを、ユーザーの対象カタログ(通常は home_<user>)に置き換えます。書き換え後、移行したツリー全体を grep し、残存するリテラルのカタログ参照を確認します。 |
spark.sql("CREATE CATALOG IF NOT EXISTS ...")(B2) | ブロッカー | IF NOT EXISTS による処理の短絡より先に権限チェックが実行されるため、カタログがすでに存在していても、非管理者ユーザーは PERMISSION_DENIED: User does not have CREATE CATALOG on Metastore に遭遇します。まず SHOW CATALOGS LIKE '...' で確認し、結果が空の場合にのみ CREATE CATALOG を実行するようにします。_resources/00-global-setup-v2.py と config* ファイルを含む、移行したツリー全体に再帰的に適用してください。 同じパターンは、ユーザーが所有していないカタログ内の CREATE SCHEMA IF NOT EXISTS および CREATE VOLUME IF NOT EXISTS にも当てはまります。 |
カテゴリ C:ストリーミング
| パターン | 重大度 | 修正方法 |
|---|---|---|
.trigger(processingTime=...) | ブロッカー | .trigger(availableNow=True) を使用し、OOM を防ぐため maxFilesPerTrigger または maxBytesPerTrigger を設定します |
.trigger(continuous=...) | ブロッカー | SDP の連続モードに移行します |
writeStream に .trigger() の呼び出しがない | ブロッカー | .trigger(availableNow=True) を必ず追加します。Spark のデフォルトは ProcessingTime("0 seconds") で、これはサポートされていません |
| Kafka source | 情報 | AvailableNow で動作します。バッチサイズの制御には maxOffsetsPerTrigger を使用します |
| Auto Loader | 情報 | 動作します。cloudFiles.maxFilesPerTrigger(cloudFiles. のプレフィックスに注意)を使用します |
カテゴリ D:設定
| パターン | 重大度 | 修正方法 |
|---|---|---|
サポートされていない spark.conf.set(...) | 警告 | 削除してください。サポートされている設定は次の6つだけです:spark.sql.shuffle.partitions、spark.sql.session.timeZone、spark.sql.ansi.enabled、spark.sql.files.maxPartitionBytes、spark.sql.legacy.timeParserPolicy、spark.databricks.execution.timeout。それ以外はすべてサーバーレスで自動調整されます。 |
| 初期化スクリプト | ブロッカー | 環境を使用してください。ノートブックの環境パネルまたは requirements.txt から依存関係を追加します。特定のバージョンを固定してください。 |
| クラスターポリシー | 情報 | コストの帰属には予算ポリシーを使用してください |
| Docker コンテナ | ブロッカー | ライブラリの管理には環境を使用してください。OS レベルのカスタマイズに Docker が必要な場合に限り、クラシックを使用してください。 |
%run ./relative/path または %run ../path | 警告 | 相対 %run パスは、サーバーレスのジョブタスクで正しく解決されない場合があります。修正方法:(1)参照先ノートブックのコードが500行未満の場合は、そのコードをインライン化します(推奨)。(2)絶対パスを指定した dbutils.notebook.run("<absolute_workspace_path>", timeout) に変換します。リポジトリの約19%で検出されています。 |
os.environ["VAR"](システム/カスタム環境変数) | 警告 | フォールバック付きの os.environ.get()、Spark 情報には spark.version、カスタム変数には dbutils.widgets を使用してください |
SET hivevar: / ${hivevar:...}(Hive 変数の置換) | ブロッカー | SQL セッション変数を使用してください:DECLARE OR REPLACE VARIABLE name = value(DBR 14.1以降) |
| 環境変数(初期化スクリプト内) | 警告 | dbutils.widgets またはジョブパラメーターを使用してください |
| Executor の数/メモリに関する明示的な設定 | 情報 | 削除してください。サーバーレスで自動スケーリングおよび自動調整されます |
廃止された Foundation Model エンドポイントへの参照。例:databricks-meta-llama-3-1-405b-instruct など(D1) | ブロッカー | ファイル名のパターンではなく、移行対象の全ファイルに対するコンテンツスキャンで検出してください。よくある参照箇所は、ai_query(endpoint => '...')、ChatDatabricks(endpoint=...)、モデルサービングの設定、Genie/AI-Functions の SQL です。現在のデフォルトである databricks-meta-llama-3-3-70b-instruct に置き換えてください。最終デプロイ前に、置換後のエンドポイントが対象ワークスペースに存在することを確認してください。 |
カテゴリ E:ライブラリ
| パターン | 重要度 | 対処方法 |
|---|---|---|
| ノートブック内の JAR ライブラリ | ブロッカー | JAR ジョブタスクとしてコンパイルします(Scala 2.13、JDK 17、環境バージョン 4 以降) |
| コンパイル済み Scala JAR の移行(バージョンと依存関係の競合) | ブロッカー | Scala 2.13.16 を対象に再コンパイルします。databricks-connect を % Provided として依存関係に追加し、カーネルにバンドルされた依存関係を % Provided として指定します。完全な手順と env-4 のクラスパスについては、JAR の移行を参照してください |
| Maven 座標 | ブロッカー | Environments で PyPI パッケージに置き換えます |
バージョンを固定していない %pip install | 警告 | バージョンを固定します:%pip install numpy==2.2.2 pandas==2.2.3 |
| カスタム Spark データソース(v1/v2 JAR) | ブロッカー | Lakehouse Federation、Lakeflow Connect、または PySpark のカスタムデータソースを使用します |
| LZO 形式のファイル | ブロッカー | Parquet または Delta に変換します |
SDP .py ライブラリファイル内で mlflow.pyfunc.spark_udf(..., env_manager='local') を介して読み込む AutoML トレーニング済みモデル(E1) | ブロッカー | SDP サーバーレスイメージには databricks-automl-runtime が含まれていないため、cloudpickle.load は ModuleNotFoundError: No module named 'databricks.automl_runtime' を発生させます。SDP .py ライブラリファイルのコメント以外で最初の行に %pip install -q databricks-automl-runtime を自動的に出力します。SDP .py ライブラリファイルでは %pip install がサポートされており、SQL フローのプランニング前に更新ごとに 1 回実行されます。同じ対処方法は、AutoML トレーニング済みモデルを読み込む SDP 以外のノートブックでも有効です。 |
| AutoML → sklearn の書き換え(A3)と既存のモデルサービングエンドポイント(E2) | 初回の再デプロイ時はブロッカー | 書き換えによりモデルのシグネチャが変更されます(例:入力から id が削除されます)。古い AutoML シグネチャに固定された既存のエンドポイントでは、HTTP 400 Failed to enforce schema of data ... Model is missing inputs ['id'] が発生し、作成や更新に失敗します。下流のサービングノートブックで、移行済みテストエンドポイント(実際のトラフィックを処理する本番エンドポイントではありません)に対して、force_update = False → force_update = True に変更し、エンドポイントが現在の prod(または Champion)エイリアスに再バインドされるようにします。変更前に、エンドポイント名が移行済みのコピーと一致することを確認してください。 |
カテゴリ F:ネットワーキング
| パターン | 重要度 | 対処方法 |
|---|---|---|
| VPC ピアリングの構成 | ブロッカー | NCC を作成し、安定した IP を取得して、リソースのファイアウォールで許可リストに追加します。同じリージョン内の S3 アクセスは変更なしで機能します。 |
| UC を使用しない直接の S3/ADLS アクセス | 警告 | UC 外部ロケーションを使用します |
カテゴリ G:サイジングとデバッグ
| パターン | 重要度 | 対処方法 |
|---|---|---|
| 大容量ドライバーメモリの構成 | 情報 | サーバーレス REPL のデフォルトは 8GB です(Environments から 16GB 以上の高メモリオプションを選択できます) |
| Spark UI への参照 | 情報 | 代わりに Query Profile を使用します:セルの出力の下にある「パフォーマンスを表示」をクリックします |
カテゴリ H:ジョブレベルの構成(dbt_task、SDP、マルチソース、デプロイの前提条件)
これらのチェックは、ノートブック本体ではなく、ジョブ/パイプラインの仕様 JSON とデプロイの前提条件を対象にします。カテゴリ A~G のノートブック単位のチェックと併せて適用してください。
| パターン | 重大度 | 修正 |
|---|---|---|
ジョブ仕様内の dbt_task ブロック(H1) | dbt ワークロードのブロッカー | 3 つのサブチェックを行います:(1)warehouse_id:高負荷が予想される、またはサーバーレスではないことが分かっているウェアハウスを、Stable/専用の DBSQL サーバーレスウェアハウスに切り替えます。(2)project_directory:移行後のワークスペースの場所(例:/Workspace/Users/<me>/<demo>-skill-migrated/...)に書き換えます。(3)libraries[]:クラシック専用の Python ホイールを、バージョンを固定したサーバーレス互換バージョンに置き換えます。dbt-databricks < 1.7.x にはフラグを付けます。 |
元のデモと同じ schema を使用してデプロイされた SDP パイプライン仕様(H2) | ブロッカー | UC は Table is already managed by pipeline <orig-id> により、並行デプロイを拒否します。ターゲットパスに移行サフィックス(例:-skill-migrated/)が含まれる場合、パイプラインのターゲット schema にサフィックスを自動で付与します(例:dbdemos_retail_c360 → dbdemos_retail_c360_skill_migrated)。スキーマをハードコードしている変換ファイル内の LIVE/STREAMING TABLE 参照にも、同じ書き換えを適用します。デプロイ前にパイプライン仕様をリントします。ターゲットテーブルがすでに存在し、別のパイプラインに属している場合は、明確なメッセージを表示して失敗させます。 |
ワークスペースの import の 10 MB 上限(H3) | 事前に検出可能な注意事項 | デプロイ前の前提条件として、databricks workspace import の前に移行済みツリーを走査し、10 MB を超えるファイルにフラグを付けます。大きなファイル(サンプル CSV、dbt seed データ、サンプルデータセットなど)は、ワークスペースへのインポートではなく UC Volumes(databricks fs cp)に振り分けます。ワークスペースへのインポートコマンドと併せて UC Volumes へのアップロードコマンドを出力し、各ファイルの配置先を示すマニフェストも含めます。ほとんどのワークロードではブロッカーになりませんが、dbt seed や大きなサンプル CSV を使用するデモではブロッカーになります。 |
bundle_config.py で上流 Git URL を宣言しているマルチソースワークロード(H4) | 診断 | これがない場合、このスキルはユーザーノートブックを誤って列挙します。bundle_config.py を解析し、上流ソースの宣言(Git URL、S3 パス)をすべてたどります。ノートブックごとに列挙する前に、参照先のリポジトリをクローンするか取得します。移行計画では「外部ソース」を主要な成果物カテゴリとして一覧に含めます。マルチソースの列挙を参照してください。具体例:dbt-on-databricks の bundle_config.py は上流の dbt-databricks-c360 リポジトリを参照しています。実際のタスクノートブックはローカルの dbdemos-notebooks/ ツリーではなく、そちらにあります。 |
必須の出力:サーバーレス環境仕様
移行の出力には、移行済みコードと併せてサーバーレス環境仕様を必ず含めてください。次の手順で生成します。
- すべての
import文と%pip install行をスキャンして、必要なパッケージを検出します - ジョブ設定から init スクリプトの
pip installコマンドを抽出します - Jobs API の
environmentsフィールドに適した JSON ブロックを生成します。
{
"environment_key": "Default",
"spec": {
"client": "2",
"dependencies": ["mlflow==2.12.1", "scikit-learn==1.3.0", "xgboost==2.0.3"]
}
}
重要:ML ランタイムライブラリ(mlflow、scikit-learn、hyperopt、xgboost、tensorflow、torch など)は、サーバーレスコンピュートにプリインストールされていません。環境仕様の dependencies に必ず明示的に記載してください。サーバーレスでは ML ランタイムを利用できません。必ず、パッケージの依存関係を明示したサーバーレス環境を使用してください。
ステップ 3:テスト — 2 ブランチ戦略
テスト用の回避策がリリースするコードに混入しないよう、テストと本番には別々のブランチを使用します。テストブランチは実験用の安全なサンドボックスであり、本番ブランチには本番で実際に必要な変更のみを含めます。
| 項目 | テストブランチ | 本番ブランチ |
|---|---|---|
| 名前のパターン | serverless-test-{job_name}-{timestamp} | serverless-prod-{job_name} |
| ベースブランチ | 任意の作業ブランチ | master である必要があります |
| 目的 | サーバーレスとの互換性を検証 | 本番環境にデプロイする |
| テスト専用の回避策 | あり(カタログのオーバーライド、サンプルデータ、日付制限) | なし |
| 互換性修正 | あり(ここで見つけます) | あり(検証済みの修正を適用します) |
| ジョブ設定の変更 | あり(テストジョブ向け) | あり(本番ジョブ向け) |
| カタログ | テストカタログ | 本番カタログ |
| PR の必要性 | なし | あり |
| master へのマージ | なし | あり |
テストブランチ(serverless-test-{job_name}-{timestamp}):一時的なブランチで、PR は不要です。
- 現在の作業ブランチからブランチを作成します
- テストデータをセットアップします。ジョブのリネージを使用して、テストカタログに上流テーブルのサンプルコピーを作成します(下記のテストデータのセットアップを参照)
- ノートブックがテストデータと本番データの両方で動作するよう、カタログをパラメーター化します(下記のカタログのパラメーター化パターンを参照)
- ステップ 2 で見つかった互換性修正をすべて適用します
- サーバーレステストジョブを作成して実行します
- 失敗した場合は、エラー出力を取得してデバッグし、修正して再試行します
- どの変更がテスト用の回避策で、どれが実際の互換性修正なのかを記録します
本番ブランチ(serverless-prod-{job_name}):master から作成し、PR が必要です。
- master から新しいブランチを作成します(テストブランチから作成しないでください)
- 実際の互換性修正のみを適用します。テスト用の回避策は適用しないでください
- ジョブ設定の変更を適用します(下記のジョブ設定の変換を参照)
- コミットして PR を作成します
テストデータのセットアップ
ジョブが本番テーブルから読み取る場合、テストジョブを本番データに向けないでください。代わりに、専用のテストカタログに上流テーブルのサンプルコピーを作成し、それらを対象にテストジョブを実行します。
推奨パターン:
- リネージ(またはノートブックの静的スキャン)から、ジョブの上流テーブルを特定します
- 各上流テーブルについて、
CREATE TABLE IF NOT EXISTS <test_catalog>.<schema>.<table> AS SELECT * FROM <prod_catalog>.<schema>.<table> LIMIT Nを実行します(一般的な N:10~1000 行) - スキーマ名は本番と同じにし、変更するのはカタログのみとします
- 処理を冪等にします。すでに存在するテーブルはスキップすることで、セットアップ手順を安全に再実行できるようにします
- 実行中の SQL ウェアハウスと、テストカタログに対する
CREATE TABLE権限が必要です
スキーマ名を保持すれば、同じノートブックコードを両方の環境で実行でき、変更するのは catalog ウィジェットの値だけです。
判断ツリー:この変更を本番環境に適用すべきか?
| 変更の種類 | 本番環境? | 理由 |
|---|---|---|
| 互換性のない Spark 設定を削除する | はい | サーバーレス互換性の修正 |
| ライブラリのバージョンを更新する | はい | サーバーレス互換性の修正 |
| DBFS パスを UC Volumes に置き換える | はい | サーバーレス互換性の修正 |
| init スクリプトを削除し、Environments を追加する | はい | サーバーレス互換性の修正 |
| ハードコードされたクラスター設定を修正する | はい | サーバーレス互換性の修正 |
| カタログをテスト用カタログに上書きする | いいえ | テスト用の回避策のみ |
| テストデータがない場合の空の DataFrame の処理 | いいえ | テスト用の回避策のみ |
| テストを高速化するために日付範囲を制限する | いいえ | テスト用の回避策のみ |
簡単な判断基準:この変更がなければ、本番環境でサーバーレス実行が失敗しますか?はいなら → 含めます。いいえなら → テストブランチのみです。
A/B 比較
両方のブランチの準備ができたら、出力を比較します。
# Compare outputs between classic and serverless runs
classic_df = spark.read.table("main.output.classic_results")
serverless_df = spark.read.table("main.output.serverless_results")
assert classic_df.count() == serverless_df.count(), "Row count mismatch"
assert classic_df.schema == serverless_df.schema, "Schema mismatch"
diff = classic_df.exceptAll(serverless_df)
assert diff.count() == 0, f"Found {diff.count()} differing rows"
一時的なブリッジ設定:サーバーレス実行が失敗する場合は、ギャップを埋めるために、サポート対象の Spark 設定(spark.sql.shuffle.partitions など)を一時的に設定できます。これらには一時的な設定であることを明記し、ワークロードが安定したら削除してください。
ステップ 4:検証 — 確認と監視
A/B 比較に合格したら、次の手順を実行します。
- 本番ブランチの PR をマージします
- 本番ジョブをサーバーレスコンピュートに切り替えます
- システムテーブル(
system.billing.usage)と予算ポリシーを使ってコストを監視します - 一時的なブリッジ設定を削除します
- コストを把握できるよう、予算アラートを設定します
移行の成果物
移行が正常に完了したら、ユーザーが作業を検証し、結果を確認できるよう、次の成果物を提示します。
| 成果物 | 内容 | 重要な理由 |
|---|---|---|
| テストブランチ名/URL | 互換性の修正とテスト用の回避策をすべて含む serverless-test-{job_name}-{timestamp} ブランチ | テスト専用の調整を含め、実験中に何が変更されたかをユーザーが確認できます |
| 本番ブランチ名/URL | 検証済みの互換性の修正のみを含む serverless-prod-{job_name} ブランチ | ここからリリースされます。ユーザーはここから PR を確認してマージします |
| テストジョブ ID と実行 URL | 移行を検証したサーバーレステストジョブ | サンプリングしたデータに対して、ノートブックがサーバーレスで正常に実行されることを証明します |
| クラシックとサーバーレスの比較 | A/B 結果の概要(行数、スキーマチェック、行単位の差分) | サーバーレスの出力がクラシックの出力と一致するという確信を得られます |
| サーバーレス環境の仕様 | environments の JSON ブロック(クライアントバージョンと固定された依存関係) | 本番ジョブの設定にそのまま貼り付けられます |
| 変更の概要 | 本番環境に適用した変更とテスト専用の変更の一覧(理由を含む) | PR レビュアー向けの監査記録になります |
成果物が1つでも欠けている場合、移行は未完了です。完了として扱わないでください。
作業を中止する条件
次の問題に対する回避策は試さず、ユーザーに報告して作業を中止してください。
- ソーステーブル、テスト用カタログ、またはワークスペースの権限エラー
- カテゴリ 3 の阻害要因(R コード、カスタム Spark データソース JAR、クラシックコンピュートが必要な機能)
- SQL ウェアハウスまたはテスト用カタログが利用できない
- エラートレースに新しい情報がないまま失敗が繰り返される場合(通常は5回以上)。その場合は、代わりに失敗レポートを作成します(失敗レポートのプロトコルを参照)。
クイック修正リファレンス
DBFS パスを UC Volumes に置き換える
# BEFORE (classic)
df = spark.read.csv("dbfs:/mnt/datalake/sales/data.csv", header=True)
df.write.parquet("dbfs:/mnt/output/results")
# AFTER (serverless)
df = spark.read.csv("/Volumes/main/sales/raw_data/data.csv", header=True)
df.write.parquet("/Volumes/main/analytics/output/results")
# Replace mounts with external volumes (SQL):
# CREATE EXTERNAL VOLUME main.data.raw_files LOCATION 's3://my-bucket/data/';
# Then use: /Volumes/main/data/raw_files/
# Pandas paths too:
# BEFORE: pd.read_csv("/dbfs/mnt/data/file.csv")
# AFTER: pd.read_csv("/Volumes/main/data/volume/file.csv")
RDD 操作を DataFrame に置き換える
from pyspark.sql import functions as F
# parallelize + map
# BEFORE:
rdd = sc.parallelize([1, 2, 3])
result = rdd.map(lambda x: x * 2).collect()
# AFTER:
df = spark.createDataFrame([(1,), (2,), (3,)], ["value"])
result = df.select((F.col("value") * 2).alias("value")).collect()
# flatMap (word splitting)
# BEFORE:
words = sc.parallelize(["hello world"]).flatMap(lambda l: l.split(" ")).collect()
# AFTER:
df = spark.createDataFrame([("hello world",)], ["line"])
words = df.select(F.explode(F.split("line", " ")).alias("word")).collect()
# groupByKey
# BEFORE:
rdd = sc.parallelize([("a", 1), ("b", 2), ("a", 3)])
grouped = rdd.groupByKey().mapValues(list).collect()
# AFTER:
df = spark.createDataFrame([("a", 1), ("b", 2), ("a", 3)], ["key", "value"])
grouped = df.groupBy("key").agg(F.collect_list("value").alias("values")).collect()
# mapPartitions → applyInPandas
# BEFORE:
def process_partition(iterator):
yield sum(iterator)
result = sc.parallelize(range(100), 4).mapPartitions(process_partition).collect()
# AFTER:
import pandas as pd
def process_group(pdf: pd.DataFrame) -> pd.DataFrame:
return pd.DataFrame({"total": [pdf["id"].sum()]})
result = (spark.range(100).repartition(4)
.groupBy(F.spark_partition_id())
.applyInPandas(process_group, schema="total long")
.collect())
# textFile
# BEFORE: rdd = sc.textFile("/mnt/data/file.txt")
# AFTER: df = spark.read.text("/Volumes/catalog/schema/volume/file.txt")
# wholeTextFiles
# BEFORE: rdd = sc.wholeTextFiles("/mnt/data/dir/")
# AFTER: df = spark.read.format("binaryFile").load("/Volumes/catalog/schema/volume/dir/")
ストリーミングトリガーを修正する
# CRITICAL: Omitting .trigger() defaults to ProcessingTime(0) — not supported on serverless
# BEFORE (fails on serverless — no trigger = ProcessingTime default):
query = df.writeStream.format("delta").outputMode("append").start(path)
# BEFORE (fails — explicit ProcessingTime):
query = df.writeStream.trigger(processingTime="10 seconds").start(path)
# AFTER (serverless compatible):
query = (df.writeStream
.format("delta")
.outputMode("append")
.trigger(availableNow=True)
.option("checkpointLocation", "/Volumes/main/data/checkpoints/stream1")
.start("/Volumes/main/data/output/stream1"))
query.awaitTermination()
# With OOM prevention (recommended for large sources):
query = (spark.readStream.format("delta")
.option("maxFilesPerTrigger", 100) # Delta/Parquet sources
.option("maxBytesPerTrigger", "10g") # Limit data per micro-batch
.load(input_path)
.writeStream
.trigger(availableNow=True)
.option("checkpointLocation", checkpoint_path)
.start(output_path))
# Kafka: use maxOffsetsPerTrigger
query = (spark.readStream.format("kafka")
.option("kafka.bootstrap.servers", "broker:9092")
.option("subscribe", "topic1")
.option("maxOffsetsPerTrigger", 100000) # Kafka-specific
.load()
.writeStream.trigger(availableNow=True).start(output_path))
# Auto Loader: use cloudFiles.maxFilesPerTrigger (note the prefix)
query = (spark.readStream.format("cloudFiles")
.option("cloudFiles.format", "json")
.option("cloudFiles.maxFilesPerTrigger", 1000) # cloudFiles. prefix
.load(landing_path)
.writeStream.trigger(availableNow=True).start(output_path))
キャッシュを削除する
# BEFORE (classic):
df = spark.read.parquet(path)
df.cache()
df.count() # materialize cache
result1 = df.filter("status = 'active'")
result2 = df.groupBy("region").agg(F.sum("revenue"))
# AFTER (serverless — remove .cache(); native support coming soon):
df = spark.read.parquet(path)
result1 = df.filter("status = 'active'")
result2 = df.groupBy("region").agg(F.sum("revenue"))
# For truly expensive intermediate results, materialize to Delta:
expensive_df.write.format("delta").mode("overwrite").saveAsTable("main.scratch.intermediate")
result = spark.table("main.scratch.intermediate")
# SQL equivalent:
# BEFORE: CACHE TABLE my_table
# AFTER: (just remove the CACHE TABLE statement)
その他のよくある修正
| パターン | 修正方法 | 完全な例 |
|---|---|---|
sc.broadcast / sc.accumulator / sqlContext.sql | SparkSession の同等機能を使用します:broadcast() 結合、df.agg()、spark.sql() | コードパターン |
| 初期化スクリプト | Environment パネルまたは requirements.txt に移動します。PySpark はインストールしないでください。バージョンを固定します。 | コードパターン |
| Hive Metastore テーブル | ブリッジとして HMS Federation(CREATE FOREIGN CATALOG)を使用するか、直接移行します(CREATE TABLE ... AS SELECT)。 | コードパターン |
| カスタム JDBC JAR | Lakehouse Federation(CREATE CONNECTION ... TYPE POSTGRESQL)または組み込み JDBC(サーバーレスで動作)を使用します。 | コードパターン |
| Spark UI によるデバッグ | Query Profile を使用します:セル出力の下にある「パフォーマンスを表示」をクリックするか、df.explain(True) を実行します。 | コードパターン |
実行時にサーバーレスを検出する
import os
is_serverless = os.getenv("IS_SERVERLESS", "").lower() == "true"
ジョブ構成をクラシックからサーバーレスに変換する
job_clusters/new_cluster を削除し、サーバーレス仕様を含む environments を追加して、job_cluster_key を environment_key に置き換え、init_scripts を削除します。JSON の完全な変更前/変更後の例と環境バージョンの対応については、構成ガイドを参照してください。
環境バージョンの対応(ワークロードが使用していた DBR バージョンに合わせます):
| クラシック DBR | サーバーレス spec.client | Python |
|---|---|---|
| 13.x、14.x | "1" | 3.10 |
| 15.x | "2" | 3.11 |
| 16.x 以降 | "3" | 3.12 |
ジョブ定義の移行
ジョブの移行では、ノートブックのコードとともにジョブ構成 JSONも変換する必要があります。エージェントは以下をすべて実行する必要があります。
初期化スクリプトからサーバーレス環境への移行:ジョブ JSON 内の init_scripts を検出します。すべての pip install コマンドを抽出し、Environment の dependencies に変換します。pip に相当するパッケージがある OS レベルのパッケージ(apt install/yum install)は変換します(例:apt install python3-opencv は opencv-python に変換)。pip に相当するパッケージがない OS レベルのパッケージは、サーバーレス非互換(カテゴリー 3)としてフラグを付けます。
クラスターライブラリ(Maven/JAR)から Environment または Volumes への移行:Python をラップする JAR の Maven 座標は、Environment 仕様内の PyPI 相当のパッケージに置き換えます。DBFS 上のカスタム JAR は /Volumes/<your_catalog>/schema/volume/ に移動し、そのパスを参照します。カスタム Spark データソース JAR(v1/v2)はカテゴリー 3 のブロッカーです。クラシックでの維持が必要なものとしてフラグを付けます。
job_clusters からサーバーレスコンピュートへの移行:job_clusters/new_cluster ブロックをすべて削除します。サーバーレス仕様を含む environments 配列を追加します。各タスクの job_cluster_key を environment_key に置き換えます。init_scripts、num_workers、node_type_id、spark_version を削除します。完全な変更前/変更後の例については、構成ガイドを参照してください。
spark_conf の移行:ノートブック内のすべての spark.conf.set(...) 呼び出しと、ジョブ JSON 内の spark_conf エントリーを確認します。それぞれについて、以下のように対応します。
- サポート対象(維持):
spark.sql.shuffle.partitions、spark.sql.session.timeZone、spark.sql.ansi.enabled、spark.sql.files.maxPartitionBytes、spark.sql.legacy.timeParserPolicy、spark.databricks.execution.timeout - 自動調整対象(コメントを付けて削除):AQE 構成、Delta の自動圧縮、エグゼキューター/ドライバーのサイズ設定、並列処理の構成
- 認証情報の構成(削除):
fs.s3a.*、fs.azure.*— UC 外部ロケーションに置き換えます - 削除する箇所ごとに、理由を説明するコードコメントを追加します:
# Removed: auto-tuned on serverlessまたは# Removed: use UC external locations instead
テスト用にカタログをパラメーター化する
dbutils.widgets.text("catalog", "main") # Default to production
catalog = dbutils.widgets.get("catalog")
df = spark.table(f"{catalog}.sales.orders")
# Pass catalog="test_catalog" as a job parameter during testing
モックテーブルのカタログマッピングとテストジョブの作成パターンについては、構成ガイドを参照してください。
失敗したサーバーレス実行をデバッグする
推測する前に、必ず w.jobs.get_run_output(run_id=...) で実際のエラーを取得してください。よくあるエラーは次のとおりです。
| エラー | 修正方法 |
|---|---|
INFINITE_STREAMING_TRIGGER_NOT_SUPPORTED | .trigger(availableNow=True) を追加します |
UNRESOLVED_COLUMN | 一時ビュー名の衝突です。一意の名前を使用します |
TABLE_OR_VIEW_NOT_FOUND | DBFS/HMS テーブルにアクセスできません。UC に移行します |
Py4JError: ... is not available | SparkContext/RDD が使用されています。DataFrame に書き換えます |
| パッケージのインストールがタイムアウトする | バージョンを固定します。PySpark を依存関係としてインストールしないでください |
ModuleNotFoundError: No module named 'mlflow' | 環境仕様の dependencies に追加します。サーバーレスでは ML ランタイムを利用できません |
SparkContext.getOrCreate() is NOT supported / RuntimeError: Only remote Spark sessions | spark.createDataFrame() または spark.range() に置き換えます |
UC_FILE_SCHEME_FOR_TABLE_CREATION_NOT_SUPPORTED | マネージドテーブルまたは /Volumes/... パスを使用します |
PERMISSION_DENIED: CREATE SCHEMA on Catalog 'main' | CREATE ステートメントの前に spark.sql("USE CATALOG <your_catalog>") を追加します |
DATA_SOURCE_NOT_FOUND: Failed to find data source | カテゴリー 3 のブロッカーです。カスタム JAR データソースにはクラシックコンピュートが必要です |
JAR の実行時に発生する NoSuchMethodError: scala.Predef$.wrapRefArray / NoClassDefFoundError: scala/Serializable | Scala のバージョン不一致です。JAR は 2.12 を対象にコンパイルされていますが、サーバーレスは 2.13.16 です。2.13.16 を対象に再コンパイルします。JAR の移行を参照してください |
JAR の実行時に org/apache/spark/... の NoClassDefFoundError が発生する | Spark が provided ではなくバンドルされています。databricks-connect % Provided に設定します(また、SparkContext/RDD のソースがあれば書き換えます)。JAR の移行を参照してください |
移行後の SyntaxError | コメントがセル区切りをまたがず、MAGIC ブロックの内側にあることを確認します |
%run による File './<name>' not found(または %run が IPython の行マジックとして実行される) | A1:同じセル内で、通常の Python コメントが # MAGIC %run の前にあります。コメントを上にある独立した # MAGIC %md セルに移動します。 |
TypeError: max() got an unexpected keyword argument 'key' | A2:from pyspark.sql.functions import * によって組み込みの max がシャドーイングされています。max(..., key=) の代わりに、ソートとインデックスを使用します。 |
TypeError: Object of type PlanMetrics is not JSON serializable | A3:automl.classify/regress/forecast はサポートされていません。DBDemos.create_mockup_automl_run のフォールバックは Spark Connect でこのエラーを発生させます。インラインの sklearn Pipeline に書き換えます。 |
NameError: cannot access free variable 'loaded_model' | A4:mlflow 2.19.0 の pyfunc.spark_udf に Spark Connect で発生するクロージャのバグがあります。ドライバー側で pyfunc.load_model と toPandas() を使用してから spark.createDataFrame を呼び出すか、mlflow>=2.20.0 に固定します。 |
ModuleNotFoundError: No module named 'databricks.automl_runtime' | E1:SDP イメージに databricks-automl-runtime がありません。SDP の .py ライブラリファイルの先頭に %pip install -q databricks-automl-runtime を出力します。 |
HTTP 400: Failed to enforce schema of data ... Model is missing inputs ['id'] | E2:AutoML から sklearn への書き換えでモデルのシグネチャが変更されています。後続処理の force_update = False を True に変更します。 |
log_model 中の get_model_version_by_alias(..., 'Champion') による RESOURCE_DOES_NOT_EXIST | M1:UC では log_model から registered_model_name= を削除し、実行後に mlflow.register_model(...) を呼び出します。 |
.latest_versions による TypeError: 'NoneType' object is not iterable | M2:UC では RegisteredModel.latest_versions は常に None です。client.search_model_versions(...) を使用し、ソートしてインデックスで取得します。 |
MlflowException: Model signature is required for registering a model to Unity Catalog | M3:UC では log_model に signature= が必要です。infer_signature(X_sample, model.predict(X_sample)) で推論し、log_model(..., signature=signature) に渡します。UC での MLflowを参照してください。 |
ai_query(endpoint => 'databricks-meta-llama-3-1-405b-instruct') の 404 | D1:Foundation Model エンドポイントは廃止されています。移行したすべてのファイルをコンテンツ検索して、databricks-meta-llama-3-3-70b-instruct に置き換えます。 |
PERMISSION_DENIED: User does not have CREATE CATALOG on Metastore(カタログが存在する場合も発生) | B2:権限チェックは IF NOT EXISTS の処理より先に実行されます。SHOW CATALOGS LIKE '...' で確認してから処理します。_resources/ や config* ファイルも含めて、再帰的に適用します。 |
SDP の並列デプロイ時に発生する Table is already managed by pipeline <pipeline-id> | H2:移行したパイプラインのターゲット schema にサフィックスを付けます(例:<orig>_skill_migrated)。 |
DELTA_FAILED_TO_MERGE_FIELDS: prediction (Double) vs prediction (Integer) | M4:AutoML から sklearn への書き換えでは float64 の予測値が生成されます。書き込み前に、二値分類器の値を IntegerType にキャストします。UC での MLflowを参照してください。 |
| 完全なエラーリファレンスと SDK のコード例については、構成ガイドを参照してください。 |
パフォーマンスモードの選択
| 基準 | パフォーマンス最適化 | 標準 |
|---|---|---|
| 起動時間 | 50 秒未満 | 4~6 分 |
| コスト | 高め | 大幅に低い |
| 利用可能な対象 | ノートブック、ジョブ、SDP | ジョブと SDP のみ |
| 最適な用途 | 対話型作業、開発、時間制約のある作業 | バッチ ETL、スケジュール済みパイプライン |
| デフォルト | はい(UI と API) | 明示的な選択が必要 |
**標準モードはノートブックでは利用できません。**ノートブックでは常にパフォーマンス最適化モードが使用されます。
知っておくべきサーバーレスのデフォルト設定
| 設定 | 値 |
|---|---|
| REPL VM メモリ | デフォルトは 8GB(大容量メモリのオプションあり) |
| 最大エグゼキューター数 | 32(Premium)、64(Enterprise)—サポート経由で引き上げ可能 |
| サポートされる Spark 設定 | 6 個のみ(上記のカテゴリ D を参照) |
| デバッグ | クエリプロファイル(Spark UI なし) |
| ANSI SQL | デフォルトで有効(設定可能) |
失敗報告プロトコル
移行に失敗した場合、または移行できないパターンに遭遇した場合は、構造化された失敗レポートを生成し、GitHub Issue を作成するためのワンステップの方法をユーザーに提示します。このフィードバックループによってスキルが学習します。これがなければ、ギャップは発見されません。
完全な秘匿化チェックリスト、URL エンコードの手順、事前入力済みリンクの例については、失敗報告を参照してください。
判断ツリー:Issue の作成を提案するタイミング
ワークロードをそのままサーバーレスに完全移行できない場合は、必ず GitHub Issue の作成を提案してください。「既知」のパターン(R、Scala、カスタム JAR データソース、JVM アクセス、サードパーティコネクター)からのレポートも、未知のパターンからのレポートと同じくらい価値があります。これにより、ユーザーがどのギャップに最も頻繁に遭遇しているかがメンテナーに伝わり、優先順位付けに役立ちます。
具体的には、次のいずれかに該当する場合は必ず提案してください。
- ワークロードにカテゴリ 3(クラシック専用)のブロッカーが含まれている — R、Scala ノートブックセル、カスタム JAR データソース、JVM/Py4J アクセス、サーバーレス版がないサードパーティコネクター、ネイティブバイナリ依存関係など。「カテゴリ 3 として文書化されている」ことは、提案を省略する理由になりません。
- 再試行を使い切った —
retry_count >= max_retries(通常は 5)で、最終ステータスが FAILED - 未知のパターン — スキルのカタログにないクラシックコンピュートの構造が検出された
- 修正しても解決しなかった — 既知の修正を適用したが、ワークロードがサーバーレスで引き続き失敗する
- 明示的なリクエスト — ユーザーが
/migration-reportを実行した
次の場合に限り、作成を提案しないでください。
- 再試行後も含め、移行が完全に成功した場合、または
- ワークロードがすでにサーバーレスに対応しており、変更が不要だった場合。
レポートの生成方法
~/.databricks-migration-skill/reports/failure-<ISO-timestamp>.json に JSON ファイルを書き込みます。ディレクトリが存在しない場合は作成してください。
スキーマ(厳守してください。自由記述のコードや識別子は使用しないでください)。
{
"report_version": "1.1",
"report_id": "<uuid-v4>",
"skill_version": "<from SKILL.md frontmatter metadata.version>",
"timestamp": "<ISO 8601 UTC>",
"failure_phase": "analyze | migrate | test | validate",
"detected_patterns": [
{"category": "A", "pattern_id": "rdd_parallelize", "count": 3}
],
"attempted_fixes": [
{"pattern_id": "rdd_parallelize", "fix_applied": "<fix_id>", "attempt_number": 1, "outcome": "failed"}
],
"final_error_category": "unknown_api | missing_library | data_access | permission | custom_data_source | jvm_access | unsupported_language | other",
"final_error_signature": "<SHA256 of top 3 stack frames, NOT the frames themselves>",
"retry_count": 5,
"total_duration_seconds": 245,
"notebook_characteristics": {
"lines_of_code": 180,
"language": "python | sql | scala | r",
"uses_streaming": false,
"uses_ml_libraries": true,
"databricks_runtime_source": "<DBR version only, no cluster identifiers>"
}
}
レポートに含めてはならない内容
必須要件 — レポートは GitHub Issues で安全に公開できるものでなければなりません。
- コードの内容は禁止 — パターン ID のみ(例:
rdd_parallelize)。コードスニペット、関数本体、1 行だけの例も含めないでください - ファイルパスは禁止 — ノートブック名、ディレクトリパス、ワークスペース URL、DBFS パスを含めないでください
- エラーメッセージのテキストは禁止 — エラーカテゴリの列挙値とハッシュ化されたシグネチャのみを含めてください
- 識別子は禁止 — テーブル名、列名、カタログ名、スキーマ名、シークレットスコープ名、ユーザーのメールアドレス、ワークスペース ID、アカウント ID を含めないでください
- 社内向け Databricks 情報は禁止 — Databricks 従業員の名前、社内コードネーム(公開ドキュメントにない製品コードネームなど)、
go/リンク、Confluence ページ ID、Google Doc ID、Slack のユーザー ID やチャンネル ID(U…、C…)、PROD-* / SEV-* / SC-* チケット番号を含めないでください - 顧客に関する情報は禁止 — 企業名、顧客システムの製品名、またはワークスペースを所有する組織を特定できる情報を含めないでください
- 認証情報は禁止 — トークン、API キー、接続文字列、JDBC URL、サービスプリンシパル ID を含めないでください
- データの説明は禁止 — 列の値のサンプル、特定のテーブルに紐づく行数、
notebook_characteristicsフィールド以外のスキーマフィンガープリントを含めないでください
匿名化の安全性チェック
レポートを作成する前に、すべての文字列フィールドを以下のパターンのチェックリストに照らして確認してください。いずれかのパターンに一致する場合は、該当するフィールドを削除してください(部分的に伏せるのではなく、空文字列にするほうが漏えいの危険を抑えられます)。
| パターン | 削除する内容 |
|---|---|
[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,} | メールアドレス |
dbfs:/、/dbfs/、s3://、abfss://、gs://、wasbs:// | クラウドストレージのパス |
https?://[a-z0-9-]+\.cloud\.databricks\.com、https?://adb-\d+\.\d+\.azuredatabricks\.net | ワークスペース URL |
U[A-Z0-9]{8,}、C[A-Z0-9]{8,} | Slack のユーザー ID / チャンネル ID |
\bgo/[a-z0-9-]+\b | go/ リンク |
| `\b(PROD | SEV |
[0-9a-f]{20,}(ヒューリスティック) | ドキュメント、ファイル、ワークスペースの ID の可能性が高いもの |
| 分析対象のノートブックに記載されたカタログ名 / スキーマ名 / テーブル名のリテラル | 削除し、"<redacted>" に置き換える |
notebook_characteristics フィールドのみが、ワークロードのメタデータを安全に記載できる場所です。このチェックリストを拡張しない限り、新しいフィールドを追加しないでください。
シリアライズ後の決定論的なスクラブ(必須)
上記のマスキングは生成時に行われ、モデルがすべてのルールを適用することを前提としています。公開 GitHub Issue に至る経路では、それだけでは不十分です。レポートを JSON にシリアライズした後、次の手順を実行してください。
- 上記の表にあるものと同じパターンに加え、分析対象のノートブックで参照されているカタログ名 / スキーマ名 / テーブル名を、最終的な JSON ファイルのリテラルテキスト検索で再チェックします。
- いずれかのパターンに一致した場合は、事前入力済み URL または
gh issue createコマンドの表示を拒否してください。ローカルファイルのパスと、一致したパターンの一覧を表示し、共有する前にユーザー自身でファイルを手動でマスキングするよう伝えてください。 - シリアライズ後のスクラブで問題がない場合に限り、事前入力済み URL を表示できます。
この決定論的なチェックは必須です。生成時にマスキングが適用されたと確信している場合でも、省略しないでください。
レポート生成後 — 出力テンプレート
上記の判断ツリーで「報告するよう提案」と示された場合、デフォルトの出力はローカルのみです。事前入力済みの URL と gh コマンドを表示するのは、ユーザーがローカルファイルを確認し、シリアライズ後のスクラブ処理(上記参照)で問題がなかったことを確認した後に限ります。
デフォルトの応答 — 必ず以下を含めてください。
- ローカルのレポートファイルのパス(
~/.databricks-migration-skill/reports/failure-<timestamp>.json。<timestamp>は実際の値に置き換えます)。 - レポートにはパターン ID とノートブックの特性のみが含まれ、コードや識別子は含まれないという一行の説明。
- 次のプロンプト:「これはドラフトです。ファイルを開いて、マスキングが適切か確認してから、共有するよう伝えてください。確認後に、事前入力済みの GitHub issue URL を生成します。」
ユーザーが明示的に確認し(例:「共有して」、「issue を登録して」、「問題ありません」)、かつ上記の決定論的なシリアライズ後のスクラブ処理で問題がなかった場合に限り、次を提示します。
- オプション A — 完全な事前入力済み
https://github.com/databricks/databricks-agent-skills/issues/new?template=migration-feedback.md&title=<…>&body=<…>URL。両方のパラメーターを URL エンコードします。 - オプション B — 文字どおりの
gh issue create --repo databricks/databricks-agent-skills …コマンド。本文ファイルにはローカルレポートを指定します。
ファイルを書き込んだターンに、URL や gh コマンドを提示しないでください。2 ターンに分けます。1 ターン目で書き込みと確認の依頼を行い、明示的な確認後の 2 ターン目で公開します。
次のラップアップテンプレートをそのまま使用し、<…> プレースホルダーを置き換えてください。
Migration could not complete. A failure report has been generated at:
~/.databricks-migration-skill/reports/failure-<timestamp>.json
The report contains anonymized diagnostic data (detected pattern IDs, error
category, retry count, notebook characteristics) and no code content or PII.
Submission is optional and opt-in.
To help improve this skill, file the report as a GitHub issue:
Option A — One-click in browser (pre-filled):
<PREFILLED_ISSUE_URL>
Option B — From the terminal (if you have the GitHub CLI installed):
gh issue create \
--repo databricks/databricks-agent-skills \
--title "<TITLE>" \
--body-file ~/.databricks-migration-skill/reports/failure-<timestamp>.json \
--label migration-skill
Before submitting, please open the JSON and confirm nothing sensitive
slipped through. We never transmit reports automatically.
<PREFILLED_ISSUE_URL> は次のように作成します。
- タイトル:
[migration-skill] <final_error_category> in <failure_phase> phase例:[migration-skill] custom_data_source in migrate phase - 本文:issue テンプレートの Markdown スケルトン(Category、Environment、Description、
```jsonで囲んだ Failure report JSON)に、レポートの JSON をインラインで埋め込みます。 - タイトルと本文の両方を URL エンコードします(スペースには
%20、#には%23、改行には%0Aなど)。 - 最終 URL:
https://github.com/databricks/databricks-agent-skills/issues/new?template=migration-feedback.md&title=<URL-encoded title>&body=<URL-encoded body>
ランタイムがファイルを書き込めない場合(サンドボックス内である、ファイルシステムへの書き込みができないなど)でも、ファイルが作成されるはずのパスを示し、オプション A と B を提示してください。ユーザーは自分で JSON をディスクに書き込めます。
実例付きの詳しい手順は、Failure Reporting を参照してください。
レポートを自動的に送信しないでください。 ユーザーのデータはユーザー自身が管理し、共有前に確認する必要があります。ユーザーが辞退した場合は、無理に促さず、ローカルレポートのパスを記録して先へ進んでください。
成功レポート
移行が成功した場合は、失敗レポートと同じ構造のワークロードごとのレポートを生成します(公開前のマスキング手順は除く)。検出されたパターンと、各ワークロードに適用した修正を記載してください。~/.databricks-migration-skill/reports/success-<timestamp>.json に書き込み、ファイルパスをユーザーに伝えてください。
複数ワークロードの移行
対象となる独立したワークロードが複数ある場合は、並行して移行します(例:ワークロードごとに 1 つのサブエージェントを使用)。Step 1.5 のとおり、1 つのワークロード内のノートブックごとの手順は順番に実行してください。
リファレンスガイド
上記の簡易修正を超える、詳細な回避策やコード例については、以下を参照してください。
- 互換性チェック — 40 件以上のすべてのチェックを含む、完全なパターン検出表
- ストリーミングの移行 — トリガーの移行、SDP の継続モード、継続ジョブ
- ネットワークとセキュリティ — VPC ピアリングから NCC への移行、Private Link、ファイアウォールの設定
- コードパターン — すべての移行パターンについての、完全な変更前/変更後のコード例
- 設定ガイド — サポート対象の Spark 設定、Environments の設定、予算ポリシー
- UC での MLflow — AutoML から sklearn への書き換え、UC 対応の登録、
latest_versionsの置き換え、spark_udfのクロージャーバグの修正、予測列の dtype の整合 - 複数ソースの列挙 — ノートブックごとの分析前に
bundle_config.pyを解析し、上流の git ソースを取得する方法 - 失敗の報告 — 移行を完了できない場合に使用する、編集済み GitHub issue URL の作成手順と秘匿化チェックリスト
- Databricks Genie Code へのインストール — Databricks ワークスペース内でこのスキルを実行する方法
- JAR の移行 — コンパイル済み Scala JAR(spark_jar_task)の移行:Scala 2.13.16、Databricks Connect、サーバーレスカーネルのクラスパスとの依存関係の競合、sbt の修正、ビルド/テスト/デプロイ
ドキュメント
- サーバーレスコンピュートの概要:https://docs.databricks.com/en/compute/serverless/
- 移行ガイド:https://docs.databricks.com/en/compute/serverless/migration
- 制限事項:https://docs.databricks.com/en/compute/serverless/limitations
- ベストプラクティス:https://docs.databricks.com/en/compute/serverless/best-practices
- サーバーレスノートブック:https://docs.databricks.com/en/compute/serverless/notebooks
- サーバーレスジョブ:https://docs.databricks.com/en/jobs/run-serverless-jobs
- サーバーレス SDP:https://docs.databricks.com/en/ldp/serverless
- Spark Connect とクラシックの比較:https://docs.databricks.com/en/spark/connect-vs-classic
- Unity Catalog のアップグレード:https://docs.databricks.com/en/data-governance/unity-catalog/upgrade/
- サポート対象の Spark 設定:https://docs.databricks.com/en/spark/conf#serverless