Витрина данных для арбитражной команды: схема от клика до выплаты

Как построить аналитическую витрину арбитража: grain, факты, измерения, click ID, статусы, валюты, ревизии, late events, тесты и воспроизводимые отчёты.

Оглавление18 разделов

Витрина арбитражной команды должна отвечать на простой вопрос: какой расход привёл к каким наблюдаемым событиям, договорным статусам, начислениям и платежам. Но эти сущности имеют разную кратность и время. Один клик может породить несколько технических событий, одна конверсия — много изменений статуса, одно начисление — несколько корректировок. Если собрать всё одним join, отчёт умножит строки и создаст прибыль из структуры базы. Архитектура начинается с grain каждой таблицы и неизменяемых фактов.

Прямой ответ

Храните клики, продуктовые события, историю статусов, расходы, начисления и платежи отдельными фактами. Связывайте их через namespace + идентификатор, сохраняйте event/received/effective time и публикуйте витрины с revision, freshness и контрольными суммами.

1. Начните с бизнес-вопросов

Перечислите решения: pacing сегодня, зрелый CPA по когорте, сверка approved, cash forecast и оценка креатива. Каждый вопрос требует собственного времени и уровня детализации.

Одна таблица не обязана обслуживать всё; семантический слой согласует определения.

Полезно создать metric contract для каждого вопроса. В нём grain, numerator, denominator, time axis, maturity, currency, filters и owner. Например, operational CPA по received events не совпадает с finance CPA по approved cohort. Обе метрики могут быть правильными, если названы честно и не используются вместо друг друга.

2. Определите grain клика

Одна строка — один принятый логический клик в namespace трекера. Повтор HTTP-запроса хранится в техническом логе, но не создаёт второй факт.

Поля: click_id, occurred_at, received_at, source, campaign, creative, placement, route version и quality flags.

Запишите зерно как контракт: одна строка представляет один клик, одно изменение статуса, один расходный срез или один агрегат кампании за дату. Если в таблице смешаны клики и дневные суммы, обычный join способен умножить деньги на число событий. Разные зерна хранят отдельно и соединяют только через контролируемую агрегацию.

Для каждой меры укажите аддитивность. Расход обычно суммируется по времени и кампании, уникальные пользователи — нет, а коэффициент конверсии нужно пересчитывать из числителя и знаменателя. Эта пометка предотвращает формально корректные, но неверные отчёты.

3. Отделите расход

Рекламная платформа может отдавать агрегированный spend без click-level связи. Fact spend хранит grain platform-account-campaign-time bucket и исходную валюту.

Нельзя равномерно распределить расход по кликам и затем выдавать полученную точность за факт. Allocation — отдельная модель.

4. Храните продуктовые события

Fact event имеет event_id, type, occurred_at, received_at, entity references и schema version. Повторная доставка меняет delivery log, но не создаёт новое событие.

События не перезаписывают клик и могут оставаться unattributed.

Event fact не должен содержать десятки изменяемых атрибутов кампании в текстовом виде. Он хранит устойчивые foreign keys и минимальный контекст as-of, а исторические dimensions восстанавливают название и свойства. Иначе переименование campaign задним числом перепишет старые события или создаст конфликт между источниками.

5. История статусов — отдельный факт

Pending, approved, rejected, reversal и correction приходят во времени. Таблица status transition хранит from, to, effective_at, received_at, reason code и source revision.

Current status — производная snapshot-витрина, а не единственная история.

6. Начисления и платежи

Accrual отражает договорный расчёт, payment — движение денег. Они связываются, но не совпадают по периоду и сумме из-за удержаний, валюты или частичных платежей.

Финансовый отчёт не строят напрямую из event value, если договор определяет другую базу.

Для сверки создают bridge table между accrual lines и payment lines с типом связи: exact, bundled, partial, adjustment или unknown. Связь не обязана быть один-к-одному. Алгоритмическое сопоставление по сумме и дате даёт candidate, но финансовый статус confirmed появляется только по документированному правилу. Неразнесённый остаток остаётся видимым.

7. Проектируйте измерения

Campaign, creative, offer, GEO и source меняются. Используйте устойчивый внутренний ключ и версии атрибутов, чтобы исторический отчёт не переписывался текущим названием.

Unknown dimension имеет отдельную строку, а не NULL, потерянный в join.

Для изменяемых справочников выберите стратегию: хранить только актуальное значение или интервалы действия версий. Если менеджер, категория или география кампании менялись, исторический отчёт часто должен показывать состояние на момент события, а не сегодняшнее название. Интервалы valid_from и valid_to делают такое соединение явным.

8. Создайте namespace идентификаторов

Одинаковая строка от двух систем не обязана описывать одну сущность. Ключ включает owner/source namespace. Crosswalk хранит подтверждённые преобразования между external и internal IDs.

Слабые временные совпадения не становятся постоянной связью.

9. Нормализуйте время

Все факты хранят UTC и исходную timezone, если она дана. Для отчёта вычисляются локальный день клика, события, обработки и выплаты.

Выбор оси времени указывается в каждой метрике.

При построении partition учитывайте late arrival: received date определяет техническую загрузку, event date — бизнес-когорту. Один event может попасть в сегодняшнюю ingest partition и обновить прошлую business partition. Orchestrator должен знать обе зависимости, а freshness dashboard — показывать до какого event date завершён пересчёт.

10. Нормализуйте валюты версионированно

Исходная сумма и currency неизменяемы. Пересчитанная сумма хранит rate, source, effective date и target currency.

Нельзя заменять исторический курс текущим без новой revision.

11. Обрабатывайте late events

Watermark определяет, до какого event time поток считается достаточно полным. Поздняя строка обновляет затронутую partition и создаёт новую revision.

Дашборд показывает preliminary/final и дату последнего пересчёта.

12. Не делайте destructive update фактов

Исправление приходит как новая версия или компенсирующая запись. Это позволяет воспроизвести отчёт as-of прошлой даты и объяснить изменение.

Snapshot current может перезаписываться, если источник истории остаётся.

Для status history используйте effective_from/effective_to или последовательность событий. Если источник прислал исправление задним числом, сохраняются received_at и source_revision. Это позволяет ответить на два вопроса: что считалось истиной вчера и какой статус применяется сейчас. Финансовая сверка без такой двухвременной логики часто необъяснима.

13. Создайте семантические метрики

Определение FTD, approved, spend, revenue и margin хранится как код и документация с версией. Dashboard вызывает одну реализацию, а не копирует формулу.

Изменение определения не должно молча продолжать тот же временной ряд.

14. Защититесь от fan-out join

Перед join проверяйте grain и ожидаемую кратность. Click → status history является one-to-many; для текущего статуса сначала строят отдельную подвыборку.

Тест сравнивает число уникальных ключей до и после соединения.

Добавьте автоматический тест multiplicity. Перед join код считает rows и distinct business keys по обеим сторонам, после — ожидаемое увеличение. Если click соединён с тремя status rows и двумя spend allocations, результат может умножиться в шесть раз. Правильный запрос сначала агрегирует каждый факт до общей grain.

15. Введите data quality tests

Uniqueness, not-null для обязательных ключей, referential coverage, допустимые переходы статусов, свежесть, контрольные суммы и диапазоны. Ошибка блокирует публикацию затронутой метрики либо помечает degraded.

Тест должен указывать владельца и выборку нарушений.

Контроль баланса сравнивает расход и события с источником в допустимом окне задержки. Проверка уникальности ловит повтор ключа, not-null — потерю обязательного поля, accepted-values — новый неизвестный статус. Важно, чтобы сбой останавливал публикацию затронутого среза, а не только создавал уведомление, которое можно проигнорировать.

16. Управляйте доступом

Сырые идентификаторы и финансовые данные доступны минимальному кругу. Аналитические витрины используют псевдонимные ключи и агрегаты.

Экспорт и изменение схемы журналируются; сроки хранения отличаются по слоям.

Доступ выдаётся по роли и минимально необходимому уровню детализации. Команде оптимизации может быть достаточно агрегатов кампании, финансам — сверочных сумм, а инженерной группе — технических идентификаторов на ограниченный срок. Один общий экспорт для всех увеличивает риск и мешает понять, кто использовал данные.

17. Документируйте lineage

Для показателя видны источники, преобразования, версия кода, дата сборки и owner. Lineage нужен не как диаграмма ради диаграммы, а чтобы оценить impact изменения.

Если поменялся reason code, команда знает, какие отчёты пересчитать.

Impact analysis можно автоматизировать через manifest моделей и tests. Перед изменением поля система показывает downstream datasets, dashboards и exports. Владелец выбирает backfill horizon и предупреждает пользователей о revision. Такой процесс не мешает развитию схемы; напротив, позволяет менять её быстро без скрытого разрушения старых отчётов.

18. Вывод

Сильная витрина не пытается спрятать сложность в одной широкой таблице. Она сохраняет отдельные факты и времена, версионирует определения и допускает неизвестные связи.

Тогда CPA, RevShare и payout можно воспроизвести, а поздняя корректировка становится объяснимой revision, а не загадочным изменением вчерашней цифры.

Практический критерий готовности витрины — способность выбрать одну выплату и пройти назад до начисления, истории статуса, события, клика и агрегата расхода, сохранив все источники времени и версии. Одновременно можно выбрать дневной total и доказать, что join не умножает сущности. Эти два теста ценнее сотни красивых графиков.

Не моделируйте отсутствующие данные как ноль

NULL, unknown, pending и zero — разные состояния. Их смешивание создаёт ложный доход, ложный отказ или неверное решение об остановке кампании.

Станьте партнёром и начните работать

Перейдите в партнёрскую программу, изучите актуальные условия и выберите подходящий формат сотрудничества.

СТАТЬ ПАРТНЁРОМ

Связанные материалы

Все статьи
Аналитика

Бюджет первого теста: как рассчитать сумму, которой хватит для решения

Как рассчитать бюджет теста рекламы через частоту события, MDE, power, стоимость трафика, зрелость, технический этап, лимит потерь и оборотный капитал.

Аналитика

Statistical power и MDE: как планировать тест конверсии до запуска

Подробный разбор statistical power, MDE и размера выборки для конверсии: baseline, alpha, beta, абсолютный эффект, кластеры, лаг и симуляция дизайна.

Аналитика

CUPED и ковариаты в рекламном эксперименте: как снизить дисперсию без магии

Как использовать CUPED и предэкспериментальные ковариаты: выбор признака, формула корректировки, missing values, сегменты, leakage, симуляция и отчёт результата.