Processing: что мы делаем с данными
Между «загружено в DWH» и «можно показать аналитику» происходит много работы. Это и есть processing — преобразования сырых данных в готовые к потреблению модели.
В этом уроке: типы трансформаций, ETL vs ELT (тизер, подробнее в M08), и обзор инструментов.
Что входит в processing
Четыре главных типа операций:
В реальном пайплайне эти операции переплетаются.
Пример: цепочка трансформаций
Дано:
raw.orders— сырые заказы из Postgresraw.customers— клиентыraw.payments— платежи из Stripe
Цель: построить mart.daily_revenue для финансового дашборда.
Шаг 1: Staging (Silver)
-- staging.stg_orders
SELECT
CAST(id AS BIGINT) AS order_id,
CAST(customer_id AS BIGINT) AS customer_id,
CAST(order_date AS DATE) AS order_date,
CAST(amount AS DECIMAL(10,2)) AS order_amount,
status
FROM raw.orders
WHERE deleted_at IS NULL -- убираем мягко удалённые
AND status != 'test'; -- убираем тестовые заказы
Что сделали: кастинг типов, фильтр мусора. Один источник = одна модель.
Шаг 2: Conforming
В разных источниках customer_id может называться по-разному: cust_id, client_id, user_id. В staging переименовываем на единое customer_id.
Шаг 3: Join (Marts)
-- mart.daily_revenue
SELECT
order_date,
c.region,
SUM(o.order_amount) AS gross_revenue,
COUNT(DISTINCT o.order_id) AS orders_count,
COUNT(DISTINCT o.customer_id) AS unique_customers
FROM staging.stg_orders o
LEFT JOIN staging.stg_customers c USING (customer_id)
WHERE o.status = 'completed'
GROUP BY order_date, c.region;
Что сделали: join, агрегация, бизнес-фильтр (status='completed').
Аналитик пишет дашборд поверх mart.daily_revenue — простой SELECT без JOIN’ов.
ETL vs ELT — тизер
Главное концептуальное различие в стиле processing: где трансформируем.
Почему ELT победил:
- Storage в облаке стал дешёвым — можно держать raw.
- Compute в DWH стал эластичным — масштабируется при тяжёлой трансформации.
- SQL — проще в эксплуатации, чем GUI-ETL.
- Git + tests + lineage встают на код, не на ETL-граф.
В 2026 году ETL остался в банках / телекоме (legacy) и в очень специальных случаях (PII-данные нельзя везти в облако сырыми). Везде остальном — ELT.
Углубление — модуль 08-etl-vs-elt.
Инструменты для processing
dbt — стандарт MDS
dbt (data build tool) — это «SQL + Git + tests» для трансформаций. Каждая модель — это SQL-файл.
-- models/marts/daily_revenue.sql
{{ config(materialized='table') }}
SELECT
order_date,
region,
SUM(amount) AS revenue
FROM {{ ref('stg_orders') }}
LEFT JOIN {{ ref('stg_customers') }} USING (customer_id)
GROUP BY 1, 2
dbt командой dbt run запускает все модели в правильном порядке (понимает зависимости через ref()). Тесты — отдельные YAML-файлы.
Почему dbt доминирует:
- SQL — все знают.
- Git — версии, code review, история.
- Lineage — автодокументация связей моделей.
- Tests — данные тестируются как код.
- dbt Cloud / dbt Core — SaaS или OSS.
Углубление — модуль 12-dbt-transformations.
Apache Spark — для тяжёлых данных
Когда SQL не хватает (custom ML-логика, петабайты, кастомные алгоритмы), берут Spark:
df = spark.read.parquet("s3://raw/orders/")
df_clean = df.filter(df.status != "test").dropna()
df_agg = df_clean.groupBy("order_date", "region") \
.agg({"amount": "sum"})
df_agg.write.parquet("s3://marts/daily_revenue/")
Spark — про распределённую обработку. Один кластер, сотни узлов, петабайты.
Apache Spark: distributed processing, RDD, DataFrame API — когда SQL недостаточноУглубление — spark-course.
Pandas / Polars — для маленьких задач
Для ad-hoc, отчётов, маленьких трансформаций (меньше 10GB), DE используют:
- Pandas — классика Python data analysis. Удобный, но медленный на больших данных.
- Polars — современная альтернатива. В 10-100x быстрее Pandas, такой же API.
- DuckDB — SQL поверх локальных файлов. Идеален для one-off аналитики.
# Polars пример
import polars as pl
df = pl.read_csv("orders.csv")
result = df.filter(pl.col("status") == "completed") \
.group_by("region") \
.agg(pl.col("amount").sum())
Где трансформации запускаются
Качество трансформаций
После трансформации обязательно тесты:
# dbt schema.yml
version: 2
models:
- name: daily_revenue
columns:
- name: order_date
tests:
- not_null
- unique # один день - одна строка на регион
- name: revenue
tests:
- not_null
- dbt_utils.expression_is_true:
expression: "> 0" # не может быть отрицательной
Без тестов твоя модель скрытно ломается при изменении источника. Углубление — модуль 15-data-quality.
Распространённые ошибки
Главные ошибки в processing:
-
Делать всё в одной гигантской SQL — 500 строк JOIN’ов в одном запросе. Нечитаемо, не тестируется, не переиспользуется. Разбивай на маленькие модели.
-
Не использовать слои (raw / staging / marts) — мешать очистку с агрегацией. Каждая модель должна делать одну вещь.
-
Не писать тесты — потом сюрприз в проде, когда выручка упала на 30% из-за NULL’ов.
-
Перезаписывать таблицы вместо incremental — для большой таблицы full refresh может стоить тысячи долларов в Snowflake.
-
Не документировать бизнес-логику — «почему мы исключаем status=‘cancelled’? Через год никто не помнит». Комментарии в SQL — must.
Попробуй сам
- Установи dbt Core + DuckDB локально (15 минут):
pip install dbt-core dbt-duckdb
dbt init my_first_project
Создай простую модель, посчитай SUM по любому CSV.
- Возьми пример «4 типа трансформаций» выше. Запиши: какие из этих типов ты УЖЕ делал в каком-нибудь Excel или SQL раньше? Это твой стартовый багаж.