Data Engineering

Medallion Architecture in Databricks: Vollständiger Implementierungs-Guide

Schritt-für-Schritt-Guide für produktionsreife Medallion-Architekturen (Bronze/Silver/Gold) auf Databricks mit Delta Lake, PySpark und Unity Catalog.

Harbinger Team3. April 20266 Min. LesezeitAktualisiert 14.5.2026
  • databricks
  • medallion-architecture
  • delta-lake
  • data-engineering
  • pyspark
  • unity-catalog
Inhaltsverzeichnis22 Abschnitte

TL;DR: Bronze = Raw-Append-Only mit Metadaten, Silver = bereinigt mit idempotentem MERGE, Gold = Business-Aggregate mit replaceWhere. Auto Loader für Bronze, Delta-Constraints + DLT-Expectations für Quality, Liquid Clustering für Gold. Klein anfangen — Bronze + Gold reicht oft.

Die Medallion-Architektur (auch Multi-Hop-Pattern genannt) ist zum De-facto-Standard für die Organisation von Data Lakes geworden. Sie bietet einen strukturierten, inkrementellen Ansatz zur Verbesserung der Datenqualität — von Roh-Ingestion bis zu Analytics-fertigen Gold-Tabellen. In diesem Guide gehen wir durch den Bau einer produktionsreifen Medallion-Pipeline auf Databricks mit Delta Lake, PySpark und Unity Catalog.


Was ist Medallion Architecture?

Die Medallion-Architektur organisiert Daten in drei Schichten:

LayerBeschreibungTypische Use-Cases
BronzeRohdaten as-is, Append-onlyAudit, Reprocessing, Lineage
SilverBereinigt, validiert, dedupliziertOperative Analytics, Feature Engineering
GoldBusiness-aggregiert, Domain-spezifischDashboards, ML-Training-Sets, Reports

Jede Schicht verfeinert die vorherige — du kannst Daten immer zur Quelle zurückverfolgen und liefert gleichzeitig saubere, performante Tabellen an Konsumenten.


Voraussetzungen

  • Databricks Runtime 12.2 LTS oder höher
  • Delta Lake (mit Databricks gebündelt)
  • Unity Catalog aktiviert (empfohlen)
  • Cloud-Storage-Mount oder Unity-Catalog-External-Location

Unity-Catalog-Struktur aufsetzen

Bevor du Code schreibst, einen klaren Namespace etablieren:

-- Create catalogs per environment
CREATE CATALOG IF NOT EXISTS prod;
CREATE CATALOG IF NOT EXISTS dev;

-- Create schemas for each medallion layer
CREATE SCHEMA IF NOT EXISTS prod.bronze;
CREATE SCHEMA IF NOT EXISTS prod.silver;
CREATE SCHEMA IF NOT EXISTS prod.gold;

Bronze-Layer: Raw-Ingestion

Der Bronze-Layer fängt Daten exakt so ein, wie sie ankommen — keine Transformationen, kein Filtering. Das ist dein Audit-Log und Sicherheitsnetz.

Auto Loader für Streaming-Ingestion

Databricks Auto Loader ist der empfohlene Weg, Files bei Scale zu ingestieren. Er verarbeitet neue Files effizient via File-Notification oder Directory-Listing:

from pyspark.sql import SparkSession
from pyspark.sql.functions import current_timestamp, input_file_name, lit

spark = SparkSession.builder.getOrCreate()

def ingest_bronze(source_path: str, target_table: str, schema_hint: str = None):
    # Incrementally ingest raw files into the Bronze layer using Auto Loader

    reader = (
        spark.readStream
        .format("cloudFiles")
        .option("cloudFiles.format", "json")
        .option("cloudFiles.schemaLocation", f"/mnt/checkpoints/{target_table}/schema")
        .option("cloudFiles.inferColumnTypes", "true")
    )

    if schema_hint:
        reader = reader.schema(schema_hint)

    df = (
        reader.load(source_path)
        .withColumn("_ingested_at", current_timestamp())
        .withColumn("_source_file", input_file_name())
        .withColumn("_batch_id", lit("manual"))
    )

    (
        df.writeStream
        .format("delta")
        .option("checkpointLocation", f"/mnt/checkpoints/{target_table}/stream")
        .option("mergeSchema", "true")
        .outputMode("append")
        .trigger(availableNow=True)
        .table(target_table)
        .awaitTermination()
    )

# Usage
ingest_bronze(
    source_path="abfss://landing@storageaccount.dfs.core.windows.net/events/",
    target_table="prod.bronze.events_raw"
)

Bronze-Kernprinzipien

  1. Niemals aus Bronze löschen — das ist deine Source of Truth
  2. Metadaten-Spalten ergänzen (_ingested_at, _source_file, _batch_id)
  3. mergeSchema=true nutzen, um Schema-Evolution sauber zu behandeln
  4. Nach Ingestion-Datum partitionieren für Performance und Lifecycle

Silver-Layer: Bereinigung und Standardisierung

Der Silver-Layer ist, wo Business-Logik startet. Hier validierst, dedupliziert, type-castest und joinst du Referenzdaten.

Idempotentes Merge mit Delta Lake

MERGE INTO (Upsert) nutzen, um Silver-Writes idempotent zu machen — sicher nach Failures wiederholbar:

from delta.tables import DeltaTable
from pyspark.sql.functions import col, to_timestamp, trim, upper, when, current_timestamp

def transform_silver_events(spark):
    # Clean and standardize raw events into the Silver layer

    bronze_df = spark.read.table("prod.bronze.events_raw")

    silver_df = (
        bronze_df
        .withColumn("event_timestamp", to_timestamp(col("event_ts"), "yyyy-MM-dd'T'HH:mm:ss'Z'"))
        .withColumn("user_id", trim(col("user_id")))
        .withColumn("event_type", upper(trim(col("event_type"))))
        .withColumn("amount", col("amount").cast("decimal(18,4)"))
        .filter(col("event_timestamp").isNotNull())
        .filter(col("user_id").isNotNull() & (col("user_id") != ""))
        .dropDuplicates(["event_id", "event_timestamp"])
        .withColumn("_silver_processed_at", current_timestamp())
    )

    return silver_df

def write_silver_merge(df, target_table: str, merge_keys: list):
    # Upsert into Silver using Delta merge for idempotency

    df.limit(0).write.format("delta").mode("ignore").saveAsTable(target_table)

    target = DeltaTable.forName(spark, target_table)

    merge_condition = " AND ".join([f"target.{k} = source.{k}" for k in merge_keys])

    (
        target.alias("target")
        .merge(df.alias("source"), merge_condition)
        .whenMatchedUpdateAll()
        .whenNotMatchedInsertAll()
        .execute()
    )

silver_df = transform_silver_events(spark)
write_silver_merge(
    df=silver_df,
    target_table="prod.silver.events",
    merge_keys=["event_id"]
)

Datenqualität mit Delta-Constraints

Datenqualität auf Tabellen-Ebene mit Delta-Constraints durchsetzen:

ALTER TABLE prod.silver.events
  ADD CONSTRAINT chk_amount_positive CHECK (amount >= 0);

ALTER TABLE prod.silver.events
  ADD CONSTRAINT chk_event_type_valid CHECK (event_type IN ('CLICK', 'PURCHASE', 'VIEW', 'SIGN_UP'));

Alternativ Databricks Delta Live Tables (DLT)-Expectations für Pipeline-Level-Qualitätskontrolle:

import dlt
from pyspark.sql.functions import col, to_timestamp

@dlt.table(name="events_silver")
@dlt.expect_or_drop("valid_amount", "amount >= 0")
@dlt.expect_or_fail("non_null_user", "user_id IS NOT NULL")
def events_silver():
    return (
        dlt.read("events_raw")
        .withColumn("event_timestamp", to_timestamp(col("event_ts")))
        .dropDuplicates(["event_id"])
    )

Gold-Layer: Business-fertige Aggregationen

Gold-Tabellen sind zweckgebaut für spezifische Konsumenten — BI-Dashboards, ML-Modelle oder APIs. Für Read-Performance optimieren.

Daily-Revenue-Aggregation bauen

from pyspark.sql.functions import (
    col, sum as spark_sum, count, countDistinct,
    date_trunc, avg, current_timestamp
)

def build_gold_daily_revenue(spark):
    # Aggregate Silver events into a daily revenue Gold table

    df = (
        spark.read.table("prod.silver.events")
        .filter(col("event_type") == "PURCHASE")
        .filter(col("event_timestamp") >= "2024-01-01")
    )

    gold_df = (
        df
        .withColumn("event_date", date_trunc("day", col("event_timestamp")))
        .groupBy("event_date", "country", "product_category")
        .agg(
            spark_sum("amount").alias("total_revenue"),
            count("event_id").alias("transaction_count"),
            countDistinct("user_id").alias("unique_buyers"),
            avg("amount").alias("avg_order_value")
        )
        .withColumn("_gold_updated_at", current_timestamp())
    )

    return gold_df

gold_df = build_gold_daily_revenue(spark)

(
    gold_df.write
    .format("delta")
    .mode("overwrite")
    .option("replaceWhere", "event_date >= '2024-01-01'")
    .partitionBy("event_date")
    .saveAsTable("prod.gold.daily_revenue")
)

Gold-Tabellen für BI-Tools optimieren

-- Optimize file sizes for efficient scans
OPTIMIZE prod.gold.daily_revenue ZORDER BY (country, product_category);

-- Enable liquid clustering for automatic optimization (DBR 13.3+)
ALTER TABLE prod.gold.daily_revenue
  CLUSTER BY (event_date, country);

-- Set table properties for BI performance
ALTER TABLE prod.gold.daily_revenue
  SET TBLPROPERTIES (
    'delta.autoOptimize.optimizeWrite' = 'true',
    'delta.autoOptimize.autoCompact' = 'true'
  );

Orchestrierung mit Databricks Workflows

Alle drei Layer in einem Databricks-Workflow verdrahten:

# workflow.yml (Databricks Asset Bundle format)
resources:
  jobs:
    medallion_pipeline:
      name: "Medallion Pipeline - Events"
      tasks:
        - task_key: bronze_ingestion
          notebook_task:
            notebook_path: ./notebooks/bronze_ingestion
          job_cluster_key: bronze_cluster

        - task_key: silver_transform
          depends_on:
            - task_key: bronze_ingestion
          notebook_task:
            notebook_path: ./notebooks/silver_transform
          job_cluster_key: standard_cluster

        - task_key: gold_aggregation
          depends_on:
            - task_key: silver_transform
          notebook_task:
            notebook_path: ./notebooks/gold_aggregation
          job_cluster_key: standard_cluster

Monitoring und Observability

Datenqualitäts-Metriken über Layer hinweg tracken:

from datetime import datetime

def log_layer_metrics(table: str, layer: str, spark):
    # Log row counts and quality metrics for observability
    df = spark.read.table(table)

    metrics = {
        "table": table,
        "layer": layer,
        "row_count": df.count(),
        "timestamp": datetime.now().isoformat()
    }

    print(f"[{layer.upper()}] {table}: {metrics['row_count']:,} rows")
    return metrics

Das Pattern lässt sich erweitern, um Metriken in eine Monitoring-Delta-Tabelle zu pushen und in Databricks-SQL-Dashboards zu visualisieren — oder Tools wie Harbinger Explorer anbinden, für plattformübergreifende Sichtbarkeit auf Pipeline-Health.


Best-Practices-Zusammenfassung

AspektEmpfehlung
Bronze-WritesAppend-only, Metadaten-Spalten
Silver-WritesIdempotentes MERGE INTO nach Natural Key
Gold-WritesreplaceWhere für inkrementellen Partition-Overwrite
Schema-EvolutionmergeSchema=true in Bronze, explizit ab Silver
DatenqualitätDelta-Constraints + DLT-Expectations
PerformanceOPTIMIZE ZORDER oder Liquid Clustering auf Gold
OrchestrierungDatabricks Workflows mit Dependency-Chains
MonitoringDelta-History + Custom-Metrics-Tabellen

FAQ

Brauche ich alle drei Layer?

Nein. Bronze + Gold reicht oft für kleinere Setups. Silver kommt dazu, wenn du saubere, wiederverwendbare Datasets brauchst, die mehrere Gold-Tabellen speisen.

Wann nutze ich replaceWhere vs MERGE?

replaceWhere für Gold-Aggregate mit klarer Partition-Grenze (z. B. eine Datums-Partition komplett neu rechnen). MERGE für Silver-Upserts mit Natural Key, wo du nicht weißt, welche Zeilen sich geändert haben.

Wie passt das in eine DSGVO-Strategie?

Bronze sollte mit Retention-Policy laufen (z. B. 90 Tage), Silver/Gold mit Lösch-Pipelines für Right-to-be-Forgotten. Personenbezogene Daten in Bronze pseudonymisieren ist häufig die sauberste Lösung.

Wie behandle ich Late-Arriving-Data?

Silver MERGE mit Watermark auf Event-Timestamp. Gold mit replaceWhere auf rückwirkenden Zeitraum (z. B. letzte 7 Tage neu rechnen).

Was, wenn meine Daten zu klein sind für drei Layer?

Unter ~100 GB ist Medallion-Overkill. Eine Staging-+Mart-Struktur in dbt reicht oft. Erst skalieren, wenn das wirklich Schmerz schafft.


Schluss

Die Medallion-Architektur ist nicht nur Ordner-Organisation — sie ist eine Disziplin, um Datenqualität, Zuverlässigkeit und Vertrauen über deinen gesamten Lakehouse zu managen. Durch die Kombination von Delta-Lake-ACID-Garantien mit Databricks-Processing-Power und Unity-Catalog-Governance bekommst du eine produktionsreife Datenplattform, die mit deiner Organisation skaliert.

Klein anfangen: schon ein Zwei-Layer-Bronze/Gold-Setup liefert enorme Vorteile gegenüber einem rohen Datensumpf. Silver dazunehmen, wenn wiederverwendbare bereinigte Datasets nötig werden.


Stand: 14. Mai 2026.

H

Geschrieben von

Harbinger Team

Cloud-, Data- und AI-Engineer in DACH. Schreibt seit 2018 über infrastruktur­kritische Tech-Entscheidungen — keine Marketing- Folien, sondern echte Trade-offs aus Production-Workloads.

Hat dir das geholfen?

Jede Woche ein neuer Artikel über DACH-Cloud, Data und AI — direkt in dein Postfach. Kein Spam, kein Marketing-Sprech.

Kein Spam. 1-Klick-Abmeldung. Datenschutz bei Loops.so.