Databricks Certified Data Engineer Associate 教科書
第2章 データ取り込みとロード(Data Ingestion and Loading, 21%)
🎯 この節の学習目標
requests 等)での取得 → DataFrame 化 → Delta 書き込みの流れを説明できる2-4 で見たとおり、対応するマネージドコネクタやパートナーコネクタがあるならそちらが優先です。しかし現実には、コネクタが対応していないデータベースや社内 API、特殊な抽出条件が必要な場面が残ります。そこで登場するのが、ノートブックに抽出コードを書き、Lakeflow Jobs(旧 Workflows)でスケジュールする自前実装パターンです。
図:JDBC / REST による自前取り込みパイプラインの構成
Spark には JDBC データソースが組み込まれており、spark.read.format("jdbc") で外部データベースのテーブルを DataFrame として読み取れます。
💡 具体例:外部 RDB のテーブルを読み取り、UC 管理テーブルへ書き込む
# 認証情報は Databricks シークレットから取得(コードに直書きしない)
user = dbutils.secrets.get(scope="ingest", key="db_user")
password = dbutils.secrets.get(scope="ingest", key="db_password")
df = (spark.read
.format("jdbc")
.option("url", "jdbc:postgresql://db.example.internal:5432/sales")
.option("dbtable", "public.orders")
.option("user", user)
.option("password", password)
.load()
)
# UC 管理 Delta テーブルへ書き込み
df.write.mode("append").saveAsTable("main.bronze.orders")
dbtable にはテーブル名のほか、括弧で囲んだ副問い合わせも指定できます。読み取り時にソース側で絞り込みたい場合は query オプションで SQL を渡す方法もあります。
いったんクラウドストレージに中間ファイルとして書き出してから 2-2・2-3 の仕組みでロードする構成も可能ですが、DataFrame として読めているなら直接 UC 管理テーブルへ書き込むのが最短です。なお ODBC は主に BI ツールなど外部クライアントから Databricks へ接続する文脈で登場する規格で、ノートブックからの読み取りでは JDBC を使うのが通常です。
JDBC 読み取りには COPY INTO や Auto Loader のような「既処理の自動記録」がありません。毎回全件を読むとソース DB に負荷がかかるため、watermark 列(更新日時や連番 ID など、単調に増える列)を使って「前回読んだところから先だけ」を抽出します。
# 前回ロード済みの最大更新日時をターゲットテーブルから取得
last_ts = (spark.table("main.bronze.orders")
.selectExpr("max(updated_at)").first()[0])
query = f"(SELECT * FROM public.orders WHERE updated_at > '{last_ts}') AS t"
df_inc = (spark.read.format("jdbc")
.option("url", jdbc_url)
.option("dbtable", query)
.option("user", user)
.option("password", password)
.load()
)
df_inc.write.mode("append").saveAsTable("main.bronze.orders")
📝 試験のポイント
「JDBC で毎回フルテーブルを読んでいて遅い・ソースに負荷がかかる」という問題文には、「更新日時などの watermark 列で増分抽出する」が対策の軸になります。増分の管理責任が仕組み側にある(COPY INTO / Auto Loader / マネージドコネクタ)か、実装者にある(JDBC / REST)かの対比は、方式選択問題でも効いてきます。
社内 API や外部サービスの REST API からの取り込みは、Python の requests などの HTTP クライアントで取得し、DataFrame に変換して Delta へ書き込みます。
💡 具体例:REST API から JSON を取得して Delta テーブルへ
import requests
token = dbutils.secrets.get(scope="ingest", key="api_token")
resp = requests.get(
"https://api.example.internal/v1/products",
headers={"Authorization": f"Bearer {token}"},
timeout=30,
)
resp.raise_for_status()
records = resp.json()["items"] # 辞書のリスト
df = spark.createDataFrame(records)
df.write.mode("overwrite").saveAsTable("main.bronze.products")
API 応答のページネーション(次ページの繰り返し取得)やレート制限への待機は、抽出コード側で実装します。取得件数が多い場合は、ループでページを集めてから一括で createDataFrame するのが基本形です。
REST 取得のコードはドライバノード上の単一プロセスで動く点に注意してください。Spark の分散処理が効くのは DataFrame 化した後です。巨大なデータを1つの API から吸い出す用途には向かず、その場合はソース側にエクスポート機能(ストレージへのファイル出力)がないかを先に検討します。
パスワードや API トークンをノートブックに直書きするのは厳禁です。Databricks シークレット(dbutils.secrets.get(scope, key))に格納し、コードからは参照だけを行います。シークレットの値はノートブックの出力上では自動的に伏せ字(REDACTED)になります。
主要なデータベースの JDBC ドライバは Databricks Runtime に同梱されていますが、それ以外のデータベースではドライバの JAR をクラスタにライブラリとしてインストールする必要があります。また、サーバーレスなど環境によってはライブラリ導入やネットワーク到達性に制約があるため、接続先への経路(プライベートネットワーク等)も含めて事前確認が必要です。
抽出ノートブックは手動実行で終わらせず、Lakeflow Jobs のタスクとして登録して定期実行します。リトライ・タイムアウト・失敗時の通知を Jobs 側に設定すれば、自前実装でも運用品質を確保できます(第4章で詳述)。
| 注意点 | 内容 |
|---|---|
| 認証情報 | シークレットで管理。コード直書き・平文の設定ファイルは不可 |
| ドライバ | 同梱外の DB はドライバ JAR のインストールが必要。環境の制約に注意 |
| 増分抽出 | watermark 列で差分のみ抽出。自動記録の仕組みはないので実装者の責任 |
| ソース負荷 | 業務 DB への大量読み取りは業務時間を避ける、読み取り専用レプリカを使うなどの配慮 |
| オーケストレーション | Lakeflow Jobs でスケジュール・リトライ・通知を構成 |
✅ この節のまとめ
spark.read.format("jdbc") で外部 DB を DataFrame として読み、saveAsTable で UC 管理テーブルへ書き込む。ODBC は主に外部クライアントから Databricks へ接続する側の規格。requests で取得 → spark.createDataFrame → Delta 書き込み。取得部分はドライバノード単一プロセスで動く。dbutils.secrets.get)で管理し、コードに直書きしない。同梱外 DB はドライバ JAR の導入が必要。問1. ノートブックから JDBC で外部データベースに接続する際の認証情報の扱いとして最も適切なものはどれか。
正解:B
認証情報はシークレットで管理し、コードからは参照のみを行うのが標準です。シークレット値はノートブック出力で自動的に伏せ字になります。Aは実行履歴やバージョン履歴に残るため「後で消す」では守れません。Cは平文かつ共有範囲が広すぎ、Dはテーブルの参照権限を持つ全員に漏えいします。
問2. JDBC で業務データベースの大きなテーブルを毎晩取り込んでいるが、毎回全件を読んでおり、実行時間とソース DB への負荷が問題になっている。最も適切な改善策はどれか。
正解:A
JDBC には既処理の自動記録がないため、増分抽出は watermark 列で自作します。これで転送量とソース負荷の両方が減ります。Bは誤りで、COPY INTO のソースはクラウドストレージ上のファイルであり、JDBC URL は指定できません。Cは読み取り自体の量が減らないためソース DB の負荷問題を解決しません。Dはソース DB への負荷をむしろ恒常化させ、取り込みの目的に反します。
問3. REST API からデータを取得して Delta テーブルに書き込むコードの流れとして正しいものはどれか。
正解:B
REST 取り込みの基本形は「HTTP クライアントで取得 → DataFrame 化 → Delta 書き込み」です。Spark には REST API を直接読むデータソースは組み込まれていないため、Aのような書き方はできません。CとDも誤りで、COPY INTO と Auto Loader のソースはクラウドストレージ上のファイルであり、HTTP エンドポイントは扱えません。
問4. JDBC / REST による自前取り込みパイプラインの運用として最も適切なものはどれか。
正解:B
自前実装の取り込みは Lakeflow Jobs(旧 Workflows)でオーケストレーションするのが標準です。スケジュールに加えリトライや通知を Jobs 側で構成することで、運用品質を確保できます。Aは属人化と実行漏れのリスクがあります。Cはクラスタを占有し続けるうえ、障害時の再開制御もできない悪手です。Dは誤りで、Jobs は任意のノートブック・スクリプトをスケジュールできます。