Собесов

DataLearn DE-101: Data Quality — какие тесты обязательны на витринах

Кейсы и метрикиData QualityЛёгкаяMiddle

Условие

«У нас в выручке за вчера резкий провал» — звонит CFO утром. На самом деле — ETL упал ночью, и витрина обновлена только наполовину. Какие data-quality тесты надо было поставить, чтобы CFO не увидел поломанную цифру? Опишите 6+ типов проверок и приведите код в dbt.

Решение

Категории проверок

  1. Свежесть (freshness) — данные обновились?
  2. Полнота (completeness) — все ли строки/партиции на месте?
  3. Уникальность (uniqueness) — нет ли дублей по PK?
  4. Ссылочная целостность — все ли FK существуют в dim?
  5. Диапазон значений — amount > 0, status в списке валидных?
  6. Аномалии — резкие отклонения от вчера/прошлой недели?
  7. Не-null — обязательные поля заполнены?
  8. Распределение — доля каждого segment не уехала?

Реализация в dbt

# models/marts/orders_daily.yml
version: 2
 
models:
  - name: orders_daily
    description: "Ежедневная агрегация заказов"
    tests:
      - dbt_utils.equal_rowcount:                   # сравниваем с источником
          compare_model: ref('stg_orders_count_daily')
 
    columns:
      - name: dt
        tests:
          - unique
          - not_null
          - dbt_utils.expression_is_true:
              expression: ">= '2020-01-01'"
 
      - name: n_orders
        tests:
          - not_null
          - dbt_utils.expression_is_true:
              expression: "> 0"
          - dbt_expectations.expect_column_values_to_be_between:
              min_value: 0
              max_value: 10000000
 
      - name: gmv
        tests:
          - not_null
          - dbt_utils.expression_is_true:
              expression: ">= 0"
 
      - name: status
        tests:
          - accepted_values:
              values: ['paid', 'refunded', 'cancelled']
 
sources:
  - name: raw
    freshness:
      warn_after:  {count: 4,  period: hour}
      error_after: {count: 12, period: hour}
    loaded_at_field: ingested_at
    tables:
      - name: orders

Аномалии (anomaly detection)

-- models/dq/orders_daily_anomalies.sql
WITH stats AS (
    SELECT AVG(n_orders) AS mu, STDDEV(n_orders) AS sd
    FROM {{ ref('orders_daily') }}
    WHERE dt BETWEEN CURRENT_DATE - 30 AND CURRENT_DATE - 1
)
SELECT dt, n_orders, mu, sd, (n_orders - mu) / sd AS z_score
FROM {{ ref('orders_daily') }}, stats
WHERE dt = CURRENT_DATE - 1
  AND ABS((n_orders - mu) / sd) > 3;
tests:
  - dbt_utils.equal_rowcount:
      compare_model: ref('orders_daily_anomalies')
      where: "dt = current_date - 1"
      expression: "= 0"        # никаких аномалий за вчера

Operational: где запускать

# CI on PR
dbt build --select state:modified+ --defer --state ./prod-manifest
 
# nightly
dbt source freshness && dbt build --select tag:nightly

При падении теста — Airflow / GitHub Action отправляет алерт в Slack, витрина не публикуется.

Контракт: "не показывать сырые данные"

В Airflow:

copy >> refresh >> dq_check >> publish_view

publish_view пересоздаёт mart.orders_daily_v_public только если dq_check зелёный. Иначе пользователи видят вчерашние данные с пометкой «stale».

Подводные камни

  1. Freshness на основе MAX(created_at) — обманчив: пайплайн может работать, но не приходят свежие события. Нужно мониторить MAX(ingested_at).
  2. unique тест на 1 млрд строк — дорого; запускать на инкременте.
  3. Hard fail vs warn: критические проверки (unique, FK, диапазоны) — error; soft (статистика) — warn.
  4. Cnt-сравнение source vs target: учитывайте late-arriving — допуск ±0.5%.
  5. Алерт-шум: 50 фейлов в день = игнор. Алертить только по критичным тестам.
  6. «Тесты только на staging» — забудьте; mart-слой надо тестировать максимально.
  7. Контрактные тесты (dbt contract) — фиксируют типы и порядок колонок, защищают от breaking changes.

Эталонный ответ

Обязательный набор DQ-тестов на витрине: freshness (макс возраст данных), uniqueness PK, not_null, accepted_values, диапазоны (gmv ≥ 0), referential integrity к dim, anomaly detection (z-score / WoW), row-count vs source. В dbt: tests: блок + dbt_utils + dbt_expectations + source freshness. Публикацию витрины делать через отдельный шаг, который запускается только при зелёных тестах.

Хочешь увидеть разбор?

Зарегистрируйся бесплатно — откроется развёрнутое решение этой задачи и ещё 4 на выбор.

Зарегистрироваться и увидеть разбор
Уже есть аккаунт? Войти