Enrichments (обогащения)#
Enrichments — автоматическое добавление колонок к источникам данных. Описываются один раз, применяются везде где нужны.
Система enrichments добавляет колонки двумя способами:
- Табличные enrichments — через LEFT JOIN с внешними таблицами
- Calculated fields — через скалярные SQL выражения
Зачем?#
В компании есть множество источников метрик, и аналитики постоянно добавляют к ним одни и те же разрезы (источники трафика, сегменты пользователей, геолокация и т.д.), дублируя SQL код.
Система обогащений централизует эту бизнес-логику, позволяя:
- Переиспользовать SQL-код в любых источниках
- Быстрее добавлять новые разрезы и поля для метрик
- Оптимизировать вычисления: система не будет джойнить то, что не нужно в конкретной задаче
Без enrichments:
-- Source A
SELECT e.*, bs.buyer_segment
FROM events e LEFT JOIN buyer_segments bs ON e.cookie_id = bs.cookie_id
-- Source B (тот же JOIN продублирован)
SELECT c.*, bs.buyer_segment
FROM clicks c LEFT JOIN buyer_segments bs ON c.cookie_id = bs.cookie_id
С enrichments:
# enrichments/buyer_segment.yaml - описали один раз
buyer_segment_cookie:
sql: SELECT cookie_id, buyer_segment FROM dma.v_buyer_segments
join_key: [cookie_id]
Обогащение будет доступно автоматически во всех источниках с cookie_id.
Табличные Enrichments#
Добавление колонок через LEFT JOIN с внешними таблицами.
Структура#
enrichment_name:
sql: |
SELECT join_key, additional_columns
FROM table
WHERE {{ pushdown_filter(key='key') }}
and event_date between :first_date and :last_date
join_key: [columns]
default_values: # Опционально
column: value
Ключевые механизмы#
1. Автоматическое применение и цепочки#
Enrichment применяется автоматически, если в source или других enrichments есть все колонки из join_key:
buyer_segment_cookie:
join_key: [cookie_id, event_date] # Применится если есть cookie_id и event_date
Цепочки enrichments:
Enrichments могут использовать колонки друг друга. Система автоматически определяет порядок через граф зависимостей:
# enrichments/user_profile.yaml
user_profile:
sql: SELECT user_id, region_id FROM ...
join_key: [user_id]
# enrichments/region_info.yaml
region_info:
sql: SELECT region_id, region_name FROM ... # Использует region_id из user_profile
join_key: [region_id]
Порядок джоинов определяется автоматически: сначала user_profile, затем region_info.
2. Pushdown Filter#
Макрос для оптимизации — добавляет фильтр внутрь запроса enrichment по уникальным значениям из source:
WHERE {{ pushdown_filter(cookie_id='cookie_id') }}
Генерирует:
WHERE cookie_id IN (SELECT DISTINCT cookie_id FROM source_data WHERE cookie_id IS NOT NULL)
Оптимизация уменьшает объем данных в JOIN в правой таблице, что благосклонно сказывается на времени выполнения и потребляемой памяти.
Синтаксис:
# Один ключ
WHERE {{ pushdown_filter(cookie_id='cookie_id') }}
# Несколько ключей
WHERE {{ pushdown_filter(cookie_id='cookie_id', user_id='user_id') }}
Имя аргумента - это называние поля из join_key, а значение - это колонка, которая существует в контексте sql-запроса.
3. Default Values#
Заполняет NULL через COALESCE:
traffic_source_cookie:
sql: SELECT cookie_id, source_name, is_paid FROM ...
join_key: [cookie_id]
default_values:
source_name: 'organic'
is_paid: false
4. Параметр гранулярности#
Enrichment может зависеть от гранулярности расчета :granularity.
Например, для расчетов m42 с месячной гранулярностью.
weekly_user_activity:
sql: |
SELECT
user_id,
DATE_TRUNC(:granularity, event_date) as metric_date,
AVG(activity_score) as avg_activity
FROM dma.user_activity
WHERE {{ pushdown_filter(user_id='user_id') }}
GROUP BY user_id, DATE_TRUNC(:granularity, event_date)
join_key: [user_id, metric_date]
Система подставит правильное значение гранулярности ('day', 'week', 'month') в зависимости от требований расчета.
Важно! Если используется granularity, то колонка с датой должна называться metric_date — зарезервированное имя специально для этих целей.
Best Practices для табличных enrichments#
- Всегда используйте
pushdown_filterдля больших таблиц - Фильтруйте по датам:
AND event_date BETWEEN :first_date AND :last_date - Проверяйте уникальность результатов sql по
join_key- важно для отсутствия дублей!
Calculated Fields#
Добавление колонок через скалярные SQL выражения, вычисляемые на лету из существующих полей.
Важно: Calculated fields могут быть только скалярными выражениями:
✅ Разрешено:
- Арифметика, CASE, COALESCE, функции дат и строк
❌ Запрещено:
- Агрегации (SUM, COUNT, AVG и т.д.)
- Оконные функции (ROW_NUMBER, RANK и т.д.)
Зачем?#
Calculated fields решают две задачи:
1. Объединение полей из разных enrichments
Когда нужно составить новое поле, используя поля из разных обогащений:
# enrichments/infmquery.yaml
logical_category:
sql: SELECT logcat_id, logical_category_id as logical_category_id_logcat FROM ...
join_key: [logcat_id]
microcategory:
sql: SELECT microcat_id, logical_category_id as logical_category_id_microcat FROM ...
join_key: [microcat_id]
calculated_fields:
# Объединяем в единое поле
logical_category_id: coalesce(logical_category_id_logcat, logical_category_id_microcat)
vertical_id: coalesce(vertical_id_logcat, vertical_id_microcat)
Теперь logical_category_id можно использовать:
- В metrics как обычное поле
- В других enrichments как
join_key - В dimensions
2. Переиспользование часто используемых скалярных выражений
Вместо дублирования вычислений в каждой метрике:
item_attr_log:
sql: SELECT item_id, event_date, sort_time, start_time, price FROM ...
join_key: [item_id, event_date]
calculated_fields:
# Один раз описали вычисление
item_age_hours: date_diff('hour', sort_time, event_datetime)
price_category:
case
when price >= 100000 then 'expensive'
when price >= 10000 then 'medium'
else 'cheap'
end
Базовый синтаксис#
# В YAML файле enrichment или source
calculated_fields:
field_name: 'SQL выражение'
Пример:
item_attr_log:
sql: |
SELECT item_id, event_date, sort_time, start_time, price, event_datetime
FROM dma.item_attr_log
WHERE {{ pushdown_filter(item_id='item_id') }}
join_key: [item_id, event_date]
calculated_fields:
item_age_hours: date_diff('hour', sort_time, event_datetime)
item_start_hours: date_diff('hour', start_time, event_datetime)
Многострочные выражения#
CASE выражения:
calculated_fields:
price_bin: |
case
when price >= 5000000 then 5000000
when price >= 3000000 then 3000000
when price >= 1000000 then 1000000
when price >= 500000 then 500000
when price >= 100000 then 100000
when price >= 10000 then 10000
when price >= 0 then 0
end
Цепочки приоритетов (Fallback)#
Несколько выражений для одного поля с приоритетом:
calculated_fields:
user_segment_market:
- coalesce(user_segment_market_joined, user_segment_market_default) # Приоритет 1
- user_segment_market_joined # Приоритет 2
- user_segment_market_default # Приоритет 3
Система попытается использовать первое доступное выражение.
Валидация#
Разрешено:
- Алфавит, цифры, подчеркивание, дефис:
field_name,field-name,field123 - Многострочные выражения
- Зависимости от других calculated fields
Запрещено:
- Имена, начинающиеся с цифры:
123field - Пробелы в именах:
field name - Циклические зависимости:
field_a: field_b,field_b: field_a - Самозависимость:
field_a: field_a * 2
Порядок резолвинга колонок#
Когда в запросе используется колонка, система ищет её в следующем порядке:
1. Поиск в source#
Сначала проверяется, есть ли колонка в source. Если да — берётся оттуда.
2. Поиск в enrichments#
Если колонки нет в source, проверяются enrichments (табличные и calculated) в порядке их определения в YAML файле.
Берётся первый enrichment, у которого: - Есть нужная колонка - join_key можно применить (все колонки из join_key доступны)
3. Зависимости между enrichments#
Enrichments могут зависеть друг от друга:
- Табличный enrichment может использовать колонку из другого табличного enrichment
- Calculated field может использовать колонки из табличных enrichments
- Табличный enrichment может использовать calculated field как
join_key
Система автоматически определяет порядок применения через граф зависимостей.
Пример:
# Сначала получаем категорию
logical_category:
sql: SELECT item_id, logical_category_id FROM dma.categories
join_key: [item_id]
# Calculated field использует колонку из enrichment
calculated_fields:
is_auto: logical_category_id = 9 # Авто
# Enrichment использует calculated field как join_key
auto_attributes:
sql: SELECT item_id, brand, model FROM dma.auto_attributes
join_key: [item_id, is_auto] # Применится только для авто
Валидация:
- ❌ Циклические зависимости запрещены
- ❌ Табличный enrichment и calculated field не могут возвращать колонку с одинаковым именем
Работа с CLI#
# Проверка применения enrichments
trisigma sl compile --source buyer_stream --dimensions category,region
# Валидация
trisigma sl validate
# Просмотр финального SQL
trisigma sl compile --metrics your_metric --dimensions your_dim
Следующие шаги#
Подробнее: Концепции → Enrichments