Данные и хранилища
~20 мин

Data Modeling

Нормализация, денормализация, SCD (Slowly Changing Dimensions), Data Vault.

Data Modeling — зачем ML-инженеру думать о структуре данных

Data Modeling — это про то, как организовать таблицы в базе данных, чтобы с ними было удобно работать. Для ML-инженера это важно по одной причине: тебе нужно быстро собирать фичи для моделей. Если данные разложены грамотно — написать SQL для feature engineering занимает 10 минут. Если хаос — ты полдня разбираешься, что где лежит и как это join-ить.

Нормализация vs денормализация — в двух словах

Нормализация — это когда каждый факт хранится ровно в одном месте. Адрес клиента — только в таблице clients, не размазан по orders, payments и ещё пяти таблицам. Обновил адрес в одном месте — всё консистентно. Денормализация — наоборот: ты осознанно дублируешь данные, чтобы запросы работали быстрее (меньше JOIN-ов). В транзакционных базах (PostgreSQL) нормализуют. В аналитических (BigQuery, ClickHouse) — денормализуют. Для ML-фичей почти всегда работаешь с денормализованными витринами.

💡 Правило для ML-инженера

Тебе не нужно самому нормализовать базы. Но нужно понимать разницу: если работаешь с продакшн-базой (PostgreSQL) — данные нормализованы, готовься к JOIN-ам. Если с DWH/витринами — данные уже подготовлены, бери и считай фичи.

Star Schema — главная модель для аналитики

Star Schema — самый частый способ организации данных в DWH. В центре — таблица фактов (fact table) с числами: выручка, количество, клики. Вокруг — таблицы измерений (dimensions) с атрибутами: кто купил, что купил, когда, откуда. Fact table узкая (ключи + числа), но содержит миллиарды строк. Dimension tables широкие (много атрибутов), но содержат тысячи строк. Фичи для ML — это по сути аналитические запросы к Star Schema: «сколько заказов у пользователя за 30 дней», «средний чек по категории».

-- Типичный запрос к Star Schema
SELECT d.month, u.segment,
    SUM(f.revenue) AS total_revenue,
    COUNT(DISTINCT f.user_key) AS unique_buyers
FROM fact_orders f
JOIN dim_date d ON f.date_key = d.date_key
JOIN dim_users u ON f.user_key = u.user_key
WHERE d.year = 2024
GROUP BY d.month, u.segment;

SCD Type 2 — как хранить историю изменений

Пользователь переехал из Москвы в Питер. Если просто перезаписать city — потеряешь историю. А для ML-модели может быть важно знать, что пользователь делал покупки из Москвы. SCD Type 2 решает это: создаётся новая строка с новым городом (valid_from, valid_to, is_current), а старая помечается как неактуальная. Для текущих данных фильтруешь WHERE is_current = TRUE, а для исторических — по дате.

⚠️ SCD и ML — подводный камень

Если строишь фичи для модели — всегда используй point-in-time join. То есть бери данные о пользователе на момент события, а не текущие. Иначе получишь data leakage: модель на обучении «увидит» будущие изменения.

Витрины данных для ML

В реальной работе ML-инженер чаще всего имеет дело с витринами (data marts) — готовые денормализованные таблицы с агрегатами. Витрина user-level фичей — одна строка на пользователя со всеми метриками. Именно из таких витрин собирается обучающая выборка.

-- Витрина фичей: одна строка = один пользователь
CREATE TABLE mart_user_features AS
SELECT
    u.user_id, u.segment,
    COUNT(o.order_id) AS total_orders,
    SUM(o.revenue) AS total_revenue,
    AVG(o.revenue) AS avg_order_value,
    CURRENT_DATE - MAX(o.created_at)::date AS days_since_last,
    COUNT(DISTINCT DATE_TRUNC('month', o.created_at)) AS active_months,
    COUNT(DISTINCT o.product_category) AS unique_categories
FROM dim_users u
LEFT JOIN fact_orders o ON u.user_key = o.user_key
WHERE u.is_current = TRUE
GROUP BY u.user_id, u.segment;

Что запомнить

  • Star Schema — основная модель в DWH: факты (числа) + dimensions (атрибуты). Знай, как с ней работать
  • Нормализация — для OLTP (PostgreSQL), денормализация — для аналитики и ML
  • SCD Type 2 — для хранения истории изменений. Важно для point-in-time фичей
  • Витрины (data marts) — твой основной источник фичей. Одна строка = одна сущность (пользователь, заказ)
  • Data Vault, Snowflake Schema — знай что существует, но в повседневной работе MLE встречается редко

🎯 На собесе

Что такое Star Schema? Факты + dimensions, денормализованные для быстрых аналитических запросов. Что такое SCD Type 2? Хранение истории через valid_from/valid_to — каждое изменение создаёт новую строку. Зачем ML-инженеру data modeling? Чтобы правильно собирать фичи: point-in-time join, нет data leakage, быстрые запросы к витринам.