What you will be able to do
- Apply a group of expectations with one collective action using the expect_all decorators
- Store expectation rules centrally and reuse them across datasets
- Build a quarantine pattern that keeps invalid rows for investigation instead of discarding them
- Choose warn, drop, quarantine, or fail for each constraint, and know when a job is needed to gate downstream work
1.Applying a set of rules at once with expect_all
Real datasets rarely have only one rule. SQL and Python both let you put several expectations on a dataset, but only Python lets you group them and give the whole group one action. The decorators are expect_all, expect_all_or_drop and expect_all_or_fail. Each takes a Python dictionary in which every key is an expectation name and every value is its constraint.
Grouping doesn't hide detail. Each expectation in the dictionary keeps its own description and reports its own metrics, so you can still see which rule a record broke. Because the dictionary is an ordinary Python object, you can apply one rule set to several datasets with different strictness.
valid_pages = {"valid_count": "count > 0", "valid_current_page": "current_page_id IS NOT NULL AND current_page_title IS NOT NULL"}
@dp.table
@dp.expect_all(valid_pages)
def raw_data():
# Create a raw dataset
@dp.table
@dp.expect_all_or_drop(valid_pages)
def prepared_data():
# Create a cleaned and prepared dataset
@dp.table
@dp.expect_all_or_fail(valid_pages)
def customer_facing_data():
# Create cleaned and prepared to share the datasetCheckpoint 1 of 5· Check yourself
A SQL-only team wants to declare a group of five constraints once and give the whole group the DROP action. What is true?
Both languages allow several expectations per dataset, but only Python's expect_all family groups them under one collective action.
“only Python allows you to group multiple expectations and specify collective actions.”Source: docs.databricks.com
2.Keeping rules outside the pipeline code
Because expect_all takes a dictionary, the rules can come from somewhere other than the pipeline source. Databricks recommends storing expectation definitions separately from pipeline logic, tagging related expectations so you can filter them, and applying the same expectations to similar datasets.
The documented pattern keeps a rules Delta table, or a Python module such as rules_module.py, with a name, a constraint and a tag for each rule. A helper get_rules(tag) returns a {name: constraint} dictionary for one tag. For example, @dp.expect_all_or_drop(get_rules('validity')) drops records from raw_farmers_market that fail any rule tagged validity. You can then audit or change the rules without editing the pipeline code. This approach is Python-only: SQL cannot load expectations dynamically from a file.
Checkpoint 2 of 5· Check yourself
Which statement about central rule repositories for expectations is correct?
The documented pattern builds a dictionary in Python and passes it to an expect_all decorator. Dynamic loading isn't supported in SQL.
“Dynamically loading expectations from a file is not supported in SQL.”Source: docs.databricks.com
Sources3
3.Quarantine: keep bad rows without letting them through
There isn't. Quarantine is a pattern you build from datasets and flows, not a fourth action. The expectations docs describe it as advanced logic to quarantine invalid records without failing or dropping data. It solves drop's weakness: dropped rows are counted, but they are gone, so nobody can look at them or reprocess them.
The best-practices guide describes it with two flows. One flow drops invalid rows from the main table. A second flow writes only the invalid rows to a separate quarantine streaming table. You can then investigate, fix and reprocess the bad data without contaminating the clean dataset.
The advanced-patterns page shows a version built on a flag column. A rules dictionary holds the constraints, and quarantine_rules combines them into one NOT(... AND ...) expression. A temporary table applies the rules with expect_all, so you get per-rule metrics without dropping anything. It also adds an is_quarantined column calculated from the combined expression and is partitioned on that column. Views downstream split the table into valid and invalid rows.
quarantine_rules = "NOT({0})".format(" AND ".join(rules.values()))
@dp.view
def raw_trips_data():
return spark.readStream.table("samples.nyctaxi.trips")
@dp.table(
temporary=True,
partition_cols=["is_quarantined"],
)
@dp.expect_all(rules)
def trips_data_quarantine():
return (
spark.readStream.table("raw_trips_data").withColumn("is_quarantined", expr(quarantine_rules))
)
@dp.view
def valid_trips_data():
return spark.read.table("trips_data_quarantine").filter("is_quarantined=false")With drop, the invalid rows would never reach the table, so there would be nothing left to quarantine. With warn (expect_all), every row is kept and every rule is still counted. The is_quarantined column then decides which rows go down the valid path and which go down the invalid path.
Checkpoint 3 of 5· Check yourself
Analysts must be able to inspect and reprocess malformed orders, but the clean orders table must never contain them. Which approach meets both needs?
Drop alone discards the rows. Fail blocks the whole update. Warn lets the rows into the clean table. Quarantine keeps the bad rows and keeps them out of the clean data.
“Route rows that fail validation to a separate streaming table by using two flows”Source: docs.databricks.com
Checkpoint 4 of 5· Exam question
A data engineer is building a silver-layer streaming table in a Lakeflow Declarative Pipeline. The business requirement states that records with a null `customer_id` must never reach the silver table, but the pipeline should keep processing subsequent batches even when such records occur, and the team wants a running count of how many rows were removed. Which decorator should the engineer apply to the transformation function?
Correct answer: B — `@dp.expect_or_drop("valid_customer_id", "customer_id IS NOT NULL")`, which excludes the null rows from the output while logging how many were removed.
- A. Rolling back the flow on every violation would stop processing entirely rather than letting the pipeline keep running, which conflicts with the requirement to keep processing subsequent batches.
- B. This satisfies all three requirements at once: null rows are excluded before reaching the silver table, the flow keeps processing later batches, and the number of dropped rows is tracked in the dataset's quality metrics.
- C. A plain expectation only warns and still writes the offending rows to the target table, which violates the requirement that null customer IDs must never reach the silver table.
- D. Grouping the rule under a fail-on-violation decorator still stops the entire update the moment a null appears, which is the same halting behavior as a single fail decorator and does not keep the pipeline running.
4.Choosing an action per constraint, and what expectations can't do
The production-readiness checklist asks you to choose the action for each constraint on purpose, not to apply one action everywhere. Use fail for conditions that should stop everything, such as a broken primary key. Use drop for records you can safely discard, with a quarantine table capturing what was dropped. Use warn only where you actively watch the trend. The checklist also expects every dataset that can receive bad data to have at least one expectation, and you to know its current pass rate from the Data quality tab or the event log.
| Situation | Action |
|---|---|
| Condition that should stop the world, such as a broken primary key | fail (expect_or_fail / ON VIOLATION FAIL UPDATE) |
| Records you can safely discard | drop (expect_or_drop / ON VIOLATION DROP ROW), plus a quarantine table |
| You need all data but want to see quality trends you actively watch | warn (expect / bare EXPECT) |
One limit catches people out. Expectations enforce data quality, not orchestration. They decide which records reach a target, but they don't conditionally run or skip other parts of the pipeline. You can build a validation table, such as a materialized view comparing row counts with expect_or_fail("no_rows_dropped", "a_count == b_count"). But a dataset that reads it does not wait for its result, so a failed validation does not stop downstream tables from updating. To gate downstream work, put the validation and the downstream logic in separate pipelines. Then orchestrate them with a job in which the downstream task depends on the validation task.
Checkpoint 5 of 5· Check yourself
A pipeline has a validation materialized view with expect_or_fail, and a reporting table in the same pipeline reads from it. The validation fails in a triggered run. Is the reporting table update blocked?
Expectations control which records are written, not which datasets run. Gating needs a job in which the downstream pipeline task depends on the validation pipeline task.
“A validation table doesn't gate its downstream tables.”Source: docs.databricks.com
Exam traps
Each one states something that sounds right. Open it to see what is actually true.
1.Quarantine is a built-in expectation action, like DROP ROW or FAIL UPDATE.Why is that wrong?
There are only three actions: warn, drop and fail. Quarantine is a pattern built from extra flows or a flag column with views that route valid and invalid records separately.
Covered in Quarantine: keep bad rows without letting them through
2.A failing validation table with expect_or_fail stops downstream tables in the same pipeline from updating.Why is that wrong?
Expectations don't orchestrate. To gate downstream work, split it into a separate pipeline that runs only after the validation pipeline's task succeeds in a job.
Covered in Choosing an action per constraint, and what expectations can't do
3.SQL can group several constraints under one collective ON VIOLATION action.Why is that wrong?
SQL allows several constraints, but each has its own action. Only Python's expect_all, expect_all_or_drop and expect_all_or_fail apply one action to a group.
Sources
Every claim above is drawn from one of these pages, quoted as it was written on the date shown.
- 1.
“When you use expect_all decorators, each expectation has its own description and reports granular metrics.”
↩︎ Applying a set of rules at once with expect_all - 2.https://docs.databricks.com/aws/en/ldp/expectationsOfficial docs
“only Python allows you to group multiple expectations and specify collective actions.”
↩︎ Applying a set of rules at once with expect_all“You can also implement advanced logic to quarantine invalid records without failing or dropping data.”
↩︎ Quarantine: keep bad rows without letting them through“only Python allows you to group multiple expectations and specify collective actions.”
↩︎ Exam trap 3 - 3.
“Store expectation definitions separately from pipeline logic.”
↩︎ Keeping rules outside the pipeline code“Dynamically loading expectations from a file is not supported in SQL.”
↩︎ Keeping rules outside the pipeline code“enable separate processing paths for valid and invalid records in downstream operations”
↩︎ Quarantine: keep bad rows without letting them through“Expectations enforce data quality, not orchestration.”
↩︎ Choosing an action per constraint, and what expectations can't do“enable separate processing paths for valid and invalid records in downstream operations”
↩︎ Exam trap 1“A validation table doesn't gate its downstream tables.”
↩︎ Exam trap 2“A validation table doesn't gate its downstream tables.”
↩︎ Checkpoint - 4.
“This lets you investigate, fix, and reprocess bad data without contaminating your clean dataset.”
↩︎ Quarantine: keep bad rows without letting them through“Route rows that fail validation to a separate streaming table by using two flows”
↩︎ Checkpoint - 5.
“drop for records you can safely discard (with a quarantine table capturing what was dropped), and warn only where you actively watch the trend.”
↩︎ Choosing an action per constraint, and what expectations can't do“fail for conditions that should stop the world (such as a broken primary key)”
↩︎ Choosing an action per constraint, and what expectations can't do