Based on the DEA-C01 exam guideReport an error
DetectAnomalies), which learns from historical statistics, with dynamic rules (last(k)), which use the previous runs as the baseline."Garbage in, garbage out." No matter how robust the pipeline, if incoming data is wrong, results are unreliable. Today we measure and enforce quality, and look at how to filter out bad data and reprocess it.
| Dimension | What it asks | Example DQDL rules |
|---|---|---|
| Completeness | Are required values non-empty? | IsComplete, Completeness |
| Uniqueness | Are there no duplicates? | IsUnique, IsPrimaryKey, Uniqueness |
| Validity | Does it follow the format, range, and allowed values? | ColumnValues, ColumnDataType, ColumnLength |
| Consistency | Are there no contradictions between tables or systems? | ReferentialIntegrity, DatasetMatch, RowCountMatch, SchemaMatch |
| Timeliness | Is the data fresh enough? | DataFreshness |
| Accuracy | Does it match real facts? | CustomSql, AggregateMatch (compare against reference data) |
💡 Related theory: Place quality validation as early in the pipeline (right after ingestion) as possible. If bad data is discovered after it has flowed all the way to the curated zone, the blast radius and the reprocessing cost grow sharply (shift-left).
Glue Data Quality is a serverless feature built on the open-source Deequ. It uses the same DQDL, but there are two places to run it, and what you can do differs.
| Item | Run on the Data Catalog | Run inside an ETL job |
|---|---|---|
| Target | Tables already registered in the catalog (S3, Redshift, JDBC, Iceberg, Hudi, Delta, etc.) | Any source Glue can read |
| Nature | Inspection of data that has accumulated (at rest) | Pre-check that filters before loading (in motion) |
| Rule recommendation | Supported | Not supported |
| Bad row identification | Not supported | Supported |
| Auto Scaling and Flex | Not supported | Supported |
| Incremental validation | Limit the range with a pushdown condition | Job bookmark |
| EventBridge and CloudWatch integration | Supported | Supported |
| Main users | Data stewards and analysts (no code) | Data engineers |
A DQDL document is case-sensitive and lists rules, separated by commas, inside a list named Rules.
Rules = [
RowCount > 1000,
IsComplete "order_id",
IsUnique "order_id",
ColumnValues "status" in ["NEW", "PAID", "SHIPPED", "CANCELLED"],
ColumnValues "amount" between 0 and 1000000,
Completeness "customer_email" > 0.95,
ColumnDataType "created_at" = "TIMESTAMP",
DataFreshness "created_at" <= 24 hours,
ReferentialIntegrity "customer_id" "customers.customer_id" >= 0.99,
(IsComplete "coupon_code") or (ColumnValues "discount" = 0),
ColumnValues "country" in ["KR", "JP", "US"] with threshold > 0.98
]| Syntax element | Meaning | Caution |
|---|---|---|
IsComplete vs Completeness | Is everything filled in vs the ratio filled in | For columns where 100% cannot be required, use the ratio rule |
between x and y | Range check | The endpoints are not included |
with threshold | Pass decision based on the ratio of values meeting the condition | Only in ColumnValues, ColumnDataType, and CustomSql |
and / or | Combine rules (composite rules) | Wrap each combined rule in parentheses |
where "..." | Filters the target rows with a SparkSQL condition before evaluating | When there is a threshold, where comes before with threshold |
CustomSql | Decides based on the result of SQL | For business rules that cannot be expressed as rules |
ReferentialIntegrity | Ratio of values that exist in the reference dataset | The reference dataset must be passed along under an alias |
compositeRuleEvaluation.method = ROW). If you do not know this, an OR rule fails unexpectedly.last(k) points to the values of the previous k runs, and when k is 2 or more you must reduce them to one number with an aggregate such as avg, min, or max.Rules = [
RowCount >= min(last(7)), # Fails if it drops below the lowest day of the last 7 runs
DetectAnomalies "RowCount" # Fails if it deviates from the historical trend
]
Analyzers = [
DistinctValuesCount "customer_id",
Completeness "customer_email"
]| Limit | Value |
|---|---|
| Rules per ruleset | 2,000 |
| Ruleset size | 65KB |
| Statistics stored per account | 100,000, retained for up to 2 years |
A fixed threshold (RowCount > 1000) produces false positives when data volume varies by weekday or season, and after the business grows it catches nothing at all. A rule built on 1 million records a day will still pass even if 25% goes missing once 2 million records a day have become normal.
| Approach | Basis | Strength | Weakness |
|---|---|---|---|
| Static rule | Absolute value set by a person | Clear meaning, works from the first run | Weak against growth and seasonality |
Dynamic rule last(k) | Values of the previous k runs | Explainable, failure is handled as a rule | Cannot see weekday patterns |
| Anomaly detection | Learned trend and seasonality | A person need not know the threshold | Needs initial data, vulnerable to contaminated learning |
💡 Related theory: Anomaly detection catches "different from usual," not "the absolute value is wrong." CloudWatch Anomaly Detection learns the normal range of a metric with the same idea. The difference is the target: CloudWatch looks at operational metrics, while Glue Data Quality looks at statistics of the data itself.
from awsgluedq.transforms import EvaluateDataQuality
from awsglue.transforms import SelectFromCollection
result = EvaluateDataQuality().process_rows(
frame=orders_dyf,
ruleset=ruleset,
publishing_options={
"dataQualityEvaluationContext": "orders_ingest",
"enableDataQualityCloudWatchMetrics": True,
"enableDataQualityResultsPublishing": True,
},
)
# Per-rule results (pass/fail, failure reason)
rule_outcomes = SelectFromCollection.apply(dfc=result, key="ruleOutcomes")
# Per-row results: original columns + 4 verdict columns
rows = SelectFromCollection.apply(dfc=result, key="rowLevelOutcomes").toDF()
valid = rows.filter(rows.DataQualityEvaluationResult == "Passed")
invalid = rows.filter(rows.DataQualityEvaluationResult == "Failed")
valid.write.mode("append").parquet("s3://lake-clean/orders/")
invalid.write.mode("append").json("s3://lake-quarantine/orders/dt=2026-06-26/")DataQualityRulesPass, DataQualityRulesFail, DataQualityRulesSkip, and DataQualityEvaluationResult. Because the rows record which rules they failed, you can store them in the quarantine area together with the failure reason.ColumnExists), are marked in the row-level result as skipped rules (DataQualityRulesSkip).A validation gate is a control point that blocks downstream progress when quality does not meet the standard.
[Glue job: ingest + DQ evaluation] → Choice state
├─ Critical rules pass AND score >= 0.95 → [load to curated]
└─ Otherwise → [quarantine] → [SNS notification] → [terminate as failed]glue.data.quality.rules.passed / failed).{
"source": ["aws.glue-dataquality"],
"detail-type": ["Data Quality Evaluation Results Available"],
"detail": { "state": ["FAILED"] }
}| Principle | Content |
|---|---|
| Block the whole batch vs split by row | If the schema is broken or the count drops sharply, block the entire batch. If only some rows have format errors, let the normal rows through and quarantine only the bad rows |
| Preserve the original | Keeping the raw zone immutable lets you reprocess from scratch at any time |
| Idempotency | Processing the same input twice must give the same result. Implement with upsert (MERGE) or partition-level overwrite |
| Partition-level reprocessing | Reprocess only the affected date partition to reduce cost and impact |
| Record failure reasons | Leave in the quarantined data which rule failed and why. A quarantine bucket without reasons becomes a graveyard no one opens |
| Tool | What it does | Clue for choosing it |
|---|---|---|
| Glue Data Quality | DQDL rules, scores, anomaly detection | "Measure and enforce quality with rules," "block inside the pipeline" |
| Glue DataBrew | No-code profiling and cleansing | "An analyst visually explores and cleanses data" |
| Glue Schema Registry | Versioning and compatibility checks for stream schemas | "Prevent producers from sending incompatible schemas" |
| CloudWatch Anomaly Detection | Learns the normal range of operational metrics | "Dynamic thresholds for metrics such as lag and error rate" |
| Athena SQL validation query | Manual, ad hoc checks after loading | "One-time check"; no rule management features |
| Symptom | Cause | Action |
|---|---|---|
| One row is wrong but the score drops sharply | The score is a rule-level ratio | Express the tolerance with ratio rules (Completeness, with threshold) |
| A rule combined with OR always fails | Each rule is evaluated over everything, then combined | Change composite rule evaluation to row level |
| Anomaly detection catches nothing | Fewer than 3 data points, or anomalous values were included in learning | Accumulate enough runs, exclude anomalous statistics |
| No notification arrives on failure | CloudWatch metric publishing is off | Keep the publishing option on |
| Count doubles after reprocessing | Append-style load | Partition overwrite or MERGE |
| A rule on a nested column is not evaluated | Nested and list types unsupported | Flatten, then evaluate |
| Question clue | Answer |
|---|---|
| "A language for defining quality rules declaratively" | DQDL |
| "It is hard to write rules from scratch; generate a draft automatically" | Rule recommendation (Data Catalog) |
| "Identify only the bad records and quarantine them" | Row-level results in an ETL job |
| "Volume changes by weekday and season; reduce false positives" | Anomaly detection / dynamic rules |
| "Keep data that fails the standard from reaching downstream" | Step Functions Choice gate + quarantine |
| "Automatic notification on failure" | EventBridge rule → SNS |
| "No duplicates even when reprocessed" | Idempotency (MERGE, partition overwrite) |
| "Control schema changes from streaming producers" | Glue Schema Registry |
Tomorrow we cover how to reconstruct what happened when a pipeline fails: CloudTrail auditing, retries, and DLQs.
last(k)) instead of fixing the threshold.Click a choice to reveal the answer and explanation.
Question 1
In AWS Glue Data Quality, which language is used to declaratively define the quality rules of a dataset?
Question 2
In a pipeline where the data volume varies greatly by day of the week and season, which approach is most appropriate for detecting anomalies with fewer false positives than a fixed threshold?
Question 3
What is the recommended action for data whose score falls below the standard at a data quality validation gate?
Question 4
When reprocessing quarantined bad data after fixing it, which property guarantees that processing the same input multiple times produces the same result?
Question 5
What is the main reason it is recommended to place data quality validation early in the pipeline (right after ingestion)?