Databricks DE Β· Topic 5.3

Data-Quality Expectations

Boolean rules on each row in an SDP pipeline. On violation: warn (keep + metric), drop (remove), or fail (abort) β€” plus the quarantine pattern. This deep dive walks each with the code.

warn / drop / failexpect_all (dict)quarantine patternevent-log metrics

The one-liner

Expectations validate each record against a SQL boolean. Choose the action: warn (keep + record metric), drop (remove bad rows), fail (abort the update), or quarantine (route bad rows aside).
πŸ›‚ Analogy: expectations are a bouncer checking IDs. Warn = let them in but note it in the logbook; Drop = turn them away quietly; Fail = shut the whole door until the problem's sorted.

Pick an action β€” see what happens to bad rows

β–Έ rule: amount >= 0 Β· two rows violate it

1 Β· The three actions

ActionBad row is…UpdateMetric?Use for
Warn (default)kept & writtencontinuesβœ… yestrack quality without blocking
Dropremoved before writecontinuesβœ… yeskeep the table clean
Failβ€”aborts / rolls back❌ notruly critical invariants

2 Β· Syntax β€” click a language

CREATE OR REFRESH STREAMING TABLE silver_orders (
  CONSTRAINT valid_id  EXPECT (order_id IS NOT NULL) ON VIOLATION DROP ROW,    -- drop
  CONSTRAINT valid_amt EXPECT (amount >= 0),                                  -- warn (default)
  CONSTRAINT has_date  EXPECT (order_date IS NOT NULL) ON VIOLATION FAIL UPDATE -- fail
) AS SELECT * FROM STREAM bronze_orders;
from pyspark import pipelines as dp

@dp.table
@dp.expect("valid_amt", "amount >= 0")                 # warn
@dp.expect_or_drop("valid_id", "order_id IS NOT NULL") # drop
@dp.expect_or_fail("has_date", "order_date IS NOT NULL")# fail
def silver_orders():
    return spark.readStream.table("bronze_orders")

# group many with a dict: @dp.expect_all / _all_or_drop / _all_or_fail
RULES = {"valid_id": "order_id IS NOT NULL", "valid_amt": "amount >= 0"}
@dp.table
@dp.expect_all_or_drop(RULES)               # drop a row failing ANY rule
def silver_orders2():
    return spark.readStream.table("bronze_orders")

Conditions are SQL booleans β€” no Python UDFs, external calls, or subqueries referencing other tables. (Legacy @dlt.expect* still works; prefer pyspark.pipelines.)

3 Β· The quarantine pattern β€” keep bad rows

Drop discards bad rows; fail halts the pipeline. To retain suspect rows, split the stream on the rules: clean β†’ silver, bad β†’ quarantine.

from pyspark.sql.functions import expr
RULES = {"valid_id": "order_id IS NOT NULL", "valid_amt": "amount >= 0"}
valid = " AND ".join(RULES.values())

@dp.table
def silver_orders():                      # clean rows only
    return spark.readStream.table("bronze_orders").filter(expr(valid))

@dp.table
def quarantined_orders():                 # bad rows kept for review/replay
    return spark.readStream.table("bronze_orders").filter(expr(f"NOT({valid})"))

4 Β· Metrics & monitoring

Why it matters

🧾 Real-world use case: an orders pipeline drops rows with null order_id, warns on amount < 0 (tracked so analysts notice), and fails the update if a critical reference table is empty.

Uses, edge cases & limitations

Common gotchas