MOC — dny 1 a 2
1. Představení Azure Databricks 2. Výběr a konfigurace compute 3. Objekty v Unity Catalogu 4. Zabezpečení Unity Catalogu 5. Governance Unity Catalogu 6. Datové modelování 7. Ingest dat
MOC — pokračování
8. Čištění a transformace dat 9. Data quality constraints · mimo osnovu 10. Datové pipelines 11. Lakeflow Jobs 12. Vývojový lifecycle · mimo osnovu 13. Monitoring a optimalizace
🏠 Rozcestník kurzu
Pod čarou — den 3
14. Průřez Microsoft Fabric 15. Power BI + Fabric + Databricks 16. Migrace z Oracle
🏠 Rozcestník kurzu
DP-750 · Kapitola 9

Data quality constraints

Validační kontroly, kontroly datových typů, schema drift a pipeline expectations
🗂 Plnění dat do Unity Catalogu, ETL a Pipelines⚠️ Mimo osnovu zkráceného kurzu
ℹ️
Mimo osnovu zkráceného kurzu: tento modul je součástí oficiálního čtyřdenního kurzu DP-750. Ve zkrácené třídenní verzi ho na kurzu neprobíráme — kapitola slouží k samostudiu a odkazovaný lab k ní zůstává plně k dispozici.

Cíle kapitoly

  • Implementovat validační kontroly na Delta tabulkách — NOT NULL, CHECK constraints a informativní PK/FK.
  • Ošetřit datové typy pomocí cast() a try_cast() a oddělit nevalidní záznamy do karantény.
  • Detekovat a řídit schema drift pomocí schema evolution módů Auto Loaderu a rescued data column.
  • Definovat expectations v Lakeflow Spark Declarative Pipelines s akcemi warn / drop / fail.
  • Monitorovat kvalitu dat přes záložku Data quality a event log pipeline.
9.1

Vrstvy obrany kvality dat

Nekvalitní data se chovají jako kontaminace — jakmile projdou do silver a gold vrstvy, šíří se do reportů, ML modelů a rozhodnutí. Dokumentace to formuluje přímo: nevalidní data „can derail analytics projects, corrupt business reports, and erode confidence in your data platform". Proto se kvalita dat nehlídá na jednom místě, ale ve vrstvách — každá vrstva chytá jiný typ problému a co proklouzne jednou, zachytí další.

Azure Databricks nabízí čtyři vestavěné mechanismy: schema enforcement (Delta Lake automaticky validuje strukturu a typy při zápisu), table constraints (pravidla přímo na tabulce, odmítnou zápis nevalidního řádku), pipeline expectations (deklarativní pravidla v Lakeflow pipelines s volitelnou reakcí) a monitoring (metriky kvality v UI a event logu). Kombinace všech čtyř se v dokumentaci označuje jako „defense in depth".

Monitoring — Data quality tab, event log, alerty průběžně sleduje všechny vrstvy pod sebou Příchozí záznam 1. Schema enforcement struktura + typy sloupců chybný typ → zápis selže 2. Table constraints NOT NULL, CHECK porušení → zápis selže 3. Expectations byznys pravidla v pipeline warn / drop / fail Co proklouzne jednou vrstvou, zachytí další — „defense in depth"
Čtyři vrstvy obrany kvality dat: schema enforcement a constraints brání zápisu nevalidních dat, expectations řídí tok v pipeline, monitoring hlídá trendy.
MechanismusKde působíReakce na porušeníTypické použití
Schema enforcementkaždý zápis do Delta tabulkyzápis selžeautomaticky, vždy zapnuto
NOT NULL / CHECK constraintzápis do konkrétní tabulkytransakce selžebatch, tvrdé garance integrity
PK / FK constraintmetadata Unity Catalogunic — informativnídokumentace modelu, BI nástroje
Pipeline expectationsdeklarativní pipelinewarn / drop / fail dle volbystreaming i batch v pipeline
💡
Tip: constraints a expectations nejsou konkurenti, ale doplňky. Constraint je poslední pojistka na tabulce (chrání ji před každým zapisovatelem, i mimo pipeline), expectation je flexibilní filtr uvnitř pipeline s metrikami. V praxi chcete obojí.
9.2

Validační kontroly: constraints na Delta tabulkách

Nejjednodušší validace je NOT NULL constraint — deklaruje se přímo v definici sloupce nebo se doplní později přes ALTER TABLE. Delta Lake pak odmítne každou transakci, která by do sloupce zapsala NULL.

SQL
-- NOT NULL primo v definici tabulky
CREATE TABLE main.silver.customers (
    customer_id INT NOT NULL,
    email STRING NOT NULL,
    first_name STRING,
    last_name STRING
);

-- dodatecne pridani na existujici tabulku
ALTER TABLE main.silver.customers ALTER COLUMN email SET NOT NULL;

Složitější byznys pravidla — rozsahy hodnot, formáty, kombinace sloupců — pokrývá CHECK constraint. Je to libovolný booleovský SQL výraz vyhodnocovaný při každém INSERT i UPDATE; porušení znamená selhání celé transakce.

SQL
ALTER TABLE main.silver.employees
  ADD CONSTRAINT valid_age CHECK (age >= 18 AND age <= 120);

ALTER TABLE main.silver.transactions
  ADD CONSTRAINT positive_amount CHECK (amount > 0);
⚠️
Pozor: PRIMARY KEY a FOREIGN KEY constraints v Unity Catalogu jsou informativní (informational) — nejsou vynucované. Delta Lake vám klidně dovolí vložit duplicitní hodnotu primárního klíče. PK/FK slouží jako dokumentace datového modelu pro lidi a BI nástroje (a optimalizátor je může využít), ale unikátnost si musíte hlídat sami — např. přes expectations nebo deduplikaci v pipeline.
SQL
-- PK je jen metadata, unikatnost NEvynucuje
CREATE TABLE main.silver.orders (
    order_id INT NOT NULL,
    customer_id INT,
    order_date DATE,
    CONSTRAINT orders_pk PRIMARY KEY (order_id)
);

-- realnou kontrolu duplicit resi napr. materialized view
CREATE OR REFRESH MATERIALIZED VIEW order_validation AS
SELECT order_id, COUNT(*) AS occurrence_count
FROM orders
GROUP BY order_id
HAVING COUNT(*) > 1;
Co když přidávám constraint na tabulku, kde už nevalidní data leží?▼

ALTER TABLE … ADD CONSTRAINT nejdřív ověří, že všechna existující data pravidlo splňují — pokud ne, příkaz selže. To je záměr: constraint garantuje stav celé tabulky, ne jen budoucích zápisů. Prakticky to znamená: nejdřív data vyčistit (nebo nevalidní řádky přesunout do karanténní tabulky), teprve pak constraint přidat. Přesné chování pro konkrétní typ constraintu ověřte v dokumentaci Delta Lake.

ℹ️
Poznámka: kdo přichází z klasických databází, čeká, že CHECK constraint nevalidní řádek prostě „odmítne" a ostatní projdou. V Delta Lake selže celá transakce — jeden špatný řádek shodí celý batch zápis. Proto se constraints hodí jako tvrdá pojistka, ale filtrování špatných řádků řešte výš v pipeline.
📚 Do hloubky na Learn: Validate data cardinality · Apply range checking (EN)
9.3

Kontroly datových typů: cast a try_cast

Řetězec tam, kde má být číslo, rozbije agregace a výpočty. První obrannou linií je opět schema enforcement: Delta Lake při zápisu porovnává typy příchozích sloupců se schématem cílové tabulky. Dokumentace: „All inserted columns must exist in the target table" a typy musí sedět nebo být bezpečně převoditelné. Zápis hodnoty 'fifty' do INT sloupce tedy selže sám od sebe.

Jenže bronze vrstva bývá plná řetězců (CSV, JSON) a převod na správné typy je vaše práce. K tomu slouží dvojice funkcí s zásadně odlišným chováním:

FunkcePři úspěchuPři selhání převoduKdy použít
cast()převedená hodnotachyba, dotaz selžetvrdá validace — chci o problému vědět hned
try_cast()převedená hodnotavrátí NULLměkká validace — chci nevalidní řádky odfiltrovat či označit
SQL
-- try_cast: selhani prevodu = NULL, ktery umim detekovat
SELECT
    raw_amount,
    try_cast(raw_amount AS DECIMAL(10,2)) AS validated_amount,
    CASE WHEN try_cast(raw_amount AS DECIMAL(10,2)) IS NULL
         THEN 'Invalid amount format' ELSE 'Valid' END AS validation_status
FROM staging_data;

Na tomto vzoru stojí praktický karanténní pattern: validní řádky přetypované do silver tabulky, nevalidní do karanténní tabulky s časovou značkou a důvodem. Nic se neztratí a datový tým má co reklamovat u zdroje.

SQL
-- validni zaznamy do silver
INSERT INTO silver_transactions
SELECT transaction_id,
       cast(amount AS DECIMAL(10,2)) AS amount,
       cast(transaction_date AS DATE) AS transaction_date
FROM bronze_transactions
WHERE try_cast(amount AS DECIMAL(10,2)) IS NOT NULL
  AND try_cast(transaction_date AS DATE) IS NOT NULL;

-- nevalidni do karanteny s duvodem
INSERT INTO quarantine_transactions
SELECT transaction_id, amount AS raw_amount, transaction_date AS raw_date,
       current_timestamp() AS quarantined_at,
       'Type validation failed' AS reason
FROM bronze_transactions
WHERE try_cast(amount AS DECIMAL(10,2)) IS NULL
   OR try_cast(transaction_date AS DATE) IS NULL;
💡
Tip: try_cast se dá zkombinovat i s CHECK constraintem — např. CHECK (try_cast(event_date_str AS DATE) IS NOT NULL) vynutí, že řetězcový sloupec je vždy parsovatelné datum, aniž byste měnili jeho typ.
9.4

Detekce a řízení schema drift

Schema drift je jiný problém než špatné hodnoty: mění se samotná struktura dat. Zdrojový systém přidá sloupec, přejmenuje pole, změní typ — a pipeline, která to nečeká, buď spadne, nebo hůř: data potichu ztratí. Výchozí chování Delta Lake je konzervativní: zápis s neznámými sloupci selže. To je bezpečné, ale u živých zdrojů potřebujete strategii.

Auto Loader nabízí pět režimů přes volbu cloudFiles.schemaEvolutionMode:

RežimChování při novém sloupci
addNewColumnsstream se zastaví; po restartu se nové sloupce přidají do schématu (výchozí, pokud není zadané schéma)
rescuestream běží dál; neočekávaná data se ukládají do rescued data column
failOnNewColumnsstream se zastaví a čeká na ruční zásah — nejpřísnější varianta
nonenové sloupce tiše ignoruje
addNewColumnsWithTypeWideningjako addNewColumns + rozšíření kompatibilních typů (INT → LONG)

Nejužitečnější kompromis pro produkci je režim rescue: pipeline nikdy nespadne kvůli struktuře a nic se neztratí. Vše, co neodpovídá očekávanému schématu, přistane jako JSON ve sloupci _rescued_data, který můžete periodicky vyhodnocovat.

PYTHON
(spark.readStream
    .format("cloudFiles")
    .option("cloudFiles.format", "json")
    .option("cloudFiles.schemaLocation", "/Volumes/main/raw/schema")
    .option("cloudFiles.schemaEvolutionMode", "rescue")
    .option("rescuedDataColumn", "_rescued_data")
    .load("/Volumes/main/raw/claims")
    .writeStream
    .option("checkpointLocation", "/Volumes/main/raw/checkpoint")
    .toTable("main.bronze.claims")
)

Pro batch zápisy a MERGE existují protějšky: .option("mergeSchema", "true") u zápisu DataFramu a syntaxe MERGE WITH SCHEMA EVOLUTION INTO v SQL — obě automaticky přidají nové sloupce do cílové tabulky.

SQL
MERGE WITH SCHEMA EVOLUTION INTO target_table t
USING source_data s
ON t.customer_id = s.customer_id
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *
⚠️
Pozor: režim none vypadá lákavě („nic nespadne"), ale nové sloupce tiše zahazuje — o změně zdroje se nedozvíte. Pokud drift chcete přežít bez ztráty dat, patří do produkce rescue; pokud chcete o driftu vědět a rozhodovat ručně, failOnNewColumns.
Provozní praxe: jak drift řídit organizačně▼

Dokumentace doporučuje: „Document your expected schemas explicitly. Store schema definitions in version control alongside your pipeline code." K tomu přidejte alerting na výskyt neprázdného _rescued_data (stačí jednoduchý dotaz v jobu) a dohodu se zdrojovými týmy o oznamování změn. Schema drift je z 80 % komunikační problém a jen z 20 % technický.

9.5

Data quality přes pipeline expectations

Expectations v deklarativních pipelines jsou pravidla kvality, která se vyhodnocují nad každým záznamem procházejícím pipeline. Každá expectation má tři části: jméno (identifikuje pravidlo v monitoringu — používejte popisná jména jako valid_customer_age), constraint (booleovský SQL výraz nad záznamem) a akci při porušení. Ve výrazu smíte použít literály, identifikátory sloupců a deterministické vestavěné SQL funkce a operátory; zakázané jsou subquery, agregační funkce, analytické a ranking window funkce a table-valued generator funkce.

ℹ️
Poznámka: materialized view s expectations se vždy refreshuje plně — inkrementální refresh v kombinaci s expectations podporovaný není. U velkých agregací s tím počítejte při návrhu; přesný aktuální stav ověřte v dokumentaci.
Záznam z upstream flow Expectation CONSTRAINT valid_amount EXPECT (amount > 0) ✓ splněno → zápis záznam jde do cílové tabulky warn (výchozí) zapíše se + metrika drop záznam se zahodí fail flow se zastaví, rollback pass violation Monitoring Data quality tab event log metriky pass/fail Všechny tři akce zapisují metriky — liší se jen osudem nevalidního záznamu
Tok záznamu přes expectation: splněný constraint pouští záznam dál, porušení řeší zvolená akce — warn (zapsat a evidovat), drop (zahodit), fail (zastavit flow).
AkcePythonSQLOsud nevalidního záznamu
Warn (výchozí)@dp.expectEXPECT (…)zapíše se, poruší se jen metrika
Drop@dp.expect_or_dropON VIOLATION DROP ROWodstraní se před zápisem
Fail@dp.expect_or_failON VIOLATION FAIL UPDATEflow se zastaví, transakce se odvolá
PYTHON
from pyspark import pipelines as dp

# dekoratory lze vrstvit — kazde pravidlo ma vlastni akci
@dp.table
@dp.expect("has_phone", "phone_number IS NOT NULL")
@dp.expect_or_drop("valid_price", "price >= 0 AND price <= 10000")
@dp.expect_or_fail("required_customer_id", "customer_id IS NOT NULL")
def validated_orders():
    return spark.readStream.table("raw.orders")
SQL
CREATE OR REFRESH STREAMING TABLE validated_orders(
    CONSTRAINT has_phone EXPECT (phone_number IS NOT NULL),
    CONSTRAINT valid_price EXPECT (price BETWEEN 0 AND 10000) ON VIOLATION DROP ROW,
    CONSTRAINT required_customer_id EXPECT (customer_id IS NOT NULL) ON VIOLATION FAIL UPDATE
) AS SELECT * FROM STREAM(raw.orders);

Pravidla nemusíte psát ke každé tabulce zvlášť. Python API umí přijmout celý slovník pravidel (@dp.expect_all_or_drop(rules)) — a ten slovník může pocházet z centrální governance tabulky v Unity Catalogu. Jedna sada pravidel označkovaná tagy, sdílená napříč pipelines:

PYTHON
from pyspark import pipelines as dp
from pyspark.sql.functions import col

def get_rules(tag):
    # nacte pravidla z governance tabulky podle tagu
    df = spark.read.table("governance.data_quality.rules").filter(col("tag") == tag).collect()
    return {row["name"]: row["constraint"] for row in df}

@dp.table
@dp.expect_all_or_drop(get_rules("financial"))
def validated_payments():
    return spark.readStream.table("raw.payments")
ℹ️
Poznámka: co se zastaví, když vystřelí fail expectation, závisí na režimu pipeline. V triggered pipeline se zastaví pouze daný flow — ostatní paralelní flows běží dál. V continuous pipeline se zastaví daný flow i všechny flows na něm závislé a pipeline oznámí důvod zastavení. Chybová hláška v event logu obsahuje i vzorek vstupních dat, která pravidlo porušila, takže diagnostika je rychlá.

Výsledky sledujete v UI: Jobs & Pipelines → vybrat pipeline → dataset s expectations → záložka Data quality. Metriky (počet prošlých a poručených záznamů na pravidlo) jdou také dotazovat programově z event logu — základ pro vlastní dashboardy a alerty.

✓
Shrnutí: constraints chrání tabulku, expectations řídí tok v pipeline, try_cast překlenuje typový chaos bronze vrstvy a rescue mód Auto Loaderu přežije schema drift bez ztráty dat. Dohromady tvoří vrstvenou obranu — žádná z nich sama nestačí.
9.6

Lab 9: Implement and Manage Data Quality Constraints in Unity Catalog (45 minut)

V roli data engineera pojišťovny ClearCover postavíte deklarativní pipeline nad denními dávkami pojistných událostí plnými chyb: NULL identifikátory, neparsovatelná data a částky, záporné hodnoty i nečekané sloupce. Přidáte expectations na nullability a rozsahy, přetypování přes col().cast() a Auto Loader s rescued data column — aby špatný záznam nikdy nedotekl k aktuárským modelům.

▶ Otevřít lab na GitHubu (EN) · Learn modul k tématu — s krátkými výukovými videy

ℹ️
Poznámka: na kurzu lab prochází lektor jako demo. Postup je krokový a samoobslužný — pokud se na něj v rámci dne nedostane, projdete si ho samostatně.
✓
Sebekontrola: 1) Jaký je rozdíl mezi chováním @dp.expect a @dp.expect_or_drop při porušení pravidla? 2) Proč PRIMARY KEY constraint v Unity Catalogu nezabrání duplicitám a čím unikátnost pohlídáte? 3) Kam se v režimu rescue ukládají data z nečekaných sloupců a jak zjistíte, že tam něco přibylo?