Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → Data lineage: происхождение данных и трассировка

Data lineage: как отслеживать происхождение данных от источника до отчёта

Data lineage: табличный и колоночный уровень, сбор из оркестратора и SQL, применение при инцидентах, аудите и оценке влияния изменений.

Прямой ответ

Data lineage (происхождение данных) — зафиксированная цепочка: откуда данные пришли, через какие преобразования прошли и где используются. Это ответ на два практических вопроса: «почему в отчёте такая цифра» и «что сломается, если я изменю эту таблицу».

Уровни детализации:

  • Табличный (dataset-level). Связи между таблицами и задачами: orders_raw → orders_curated → mart_daily_sales. Дешёв в реализации, достаточен для оценки влияния.
  • Колоночный (column-level). Связи между полями: mart_daily_sales.revenue ← sum(orders_curated.total). Нужен для аудита определений метрик и разбора расхождений.
  • Уровень значений (value-level). Отслеживание конкретных записей через цепочку. Применяется редко, в основном в задачах трассируемости и расследований.

Источники информации о lineage:

  1. Оркестратор. DAG в Airflow даёт связи между задачами и расписание; сам по себе он не знает структуры таблиц, но задаёт порядок исполнения.
  2. Трансформационный слой. dbt строит граф моделей из SQL и ref(), поэтому lineage появляется «бесплатно» вместе с документацией и тестами.
  3. Парсер SQL. Разбор запросов позволяет вывести колоночные связи даже для кода, который не описан декларативно.
  4. Журналы СУБД и запросов. pg_stat_statements, system.query_log в ClickHouse показывают, кто и какие таблицы читает — это lineage потребления.

Практическая ценность:

  • Оценка влияния. Перед изменением схемы видно, какие витрины и отчёты затронуты.
  • Разбор инцидентов. Путь от неверной цифры в дашборде к конкретной загрузке занимает минуты вместо дней.
  • Аудит и регуляторика. Для персональных данных важно показать, где они обрабатываются и куда передаются.
  • Борьба с «теневыми» данными. Если таблицу никто не читает, её можно вывести из эксплуатации; если читает неизвестный процесс — это риск.

Практика: минимально работающая система lineage

Шаг 1. Декларативные связи в коде. Все трансформации — в dbt-моделях с ref(), а не в ручных скриптах. Это даёт граф моделей и тесты — см. проверки качества данных.

Шаг 2. Метаданные в репозитории. Для каждой модели фиксируем: владельца, источник, назначение, SLA по свежести. Пример описания:

models:
  - name: mart_daily_sales
    description: "Ежедневная выручка по регионам; источник — orders_curated"
    meta:
      owner: data-team
      sla_freshness: "08:00 MSK"
      upstream: [orders_curated, dim_customer]
      downstream_consumers: [finance_report, marketing_dashboard]

Шаг 3. Журнал загрузок. Каждая загрузка пишет строку в служебную таблицу: идентификатор запуска, период данных, число строк, длительность, версия кода. Это «доказательная база» при разборе расхождений.

CREATE TABLE etl_run_log (
  run_id      TEXT PRIMARY KEY,
  model_name  TEXT NOT NULL,
  data_date   DATE NOT NULL,
  rows_loaded BIGINT,
  started_at  TIMESTAMPTZ,
  finished_at TIMESTAMPTZ,
  code_version TEXT
);

Шаг 4. Картография потребления. Регулярно собирайте список читателей таблиц из журналов СУБД и сверяйте с известными потребителями. Неизвестный читатель — повод разобраться, а не игнорировать.

Рекомендации:

  1. Начинайте с табличного уровня. Колоночный lineage дорог в поддержке; внедряйте его для критичных метрик, а не для всего хранилища.
  2. Не стройте lineage «вручную» в вики. Документация, которую не генерирует код, устаревает за месяц и начинает вводить в заблуждение.
  3. Связывайте lineage с проверками. Если известно, что витрина зависит от трёх загрузок, то падение любой из них должно блокировать публикацию витрины.
  4. Фиксируйте определения метрик. Расхождения между отчётами почти всегда про разные определения, а не про разные данные.

Практический сценарий: цифра в дашборде не сходится с финансовым отчётом

Контекст: маркетинг видит выручку на 3 % выше, чем финансы. Раньше такой разбор занимал два дня переписки.

  1. Идём по lineage от дашборда. Витрина marketing_dashboard строится из mart_marketing_sales, которая читает orders_curated без фильтра по статусу.
  2. Сравниваем с финансовым путём. finance_report использует mart_daily_sales, где применён фильтр status IN ('paid','shipped').
  3. Локализация. Расхождение дают заказы в статусе cancelled, которые попали в маркетинговую витрину. Это не ошибка данных, а разные определения меры.
  4. Решение. Фиксируем единое определение выручки в семантическом слое; обе витрины переводим на общую меру; в описании моделей указываем, какие статусы входят в расчёт.
  5. Профилактика. Добавляем в CI проверку: витрины, использующие одну меру, дают одинаковый результат на контрольном периоде. Такие сверки — часть набора проверок качества.

Результат: расхождение устранено за два часа, причина задокументирована. Вывод: lineage ускоряет не «поиск таблиц», а согласование определений — именно там живёт большинство расхождений.

FAQ

Нужен ли отдельный инструмент для lineage? На старте достаточно графа dbt и журнала загрузок. Специализированные каталоги данных оправданы, когда хранилище обслуживает несколько команд, появляются нетривиальные потребители и требуется колоночный уровень с поиском по метаданным.

Как поддерживать lineage при ручных SQL-скриптах? Либо переводить скрипты в декларативную форму, либо извлекать связи парсером SQL из журналов выполнения. Второй вариант даёт неполную картину: он не знает намерения, только фактические обращения.

Что делать с lineage в потоковых пайплайнах? Фиксируйте связи «топик → таблица» и версии схем сообщений. При изменении схемы важно видеть, какие потребители затронуты; правила совместимости разобраны в статье про schema registry.

Как lineage связан с GDPR и удалением данных? Lineage показывает, в какие таблицы и витрины попали персональные данные, то есть где именно нужно выполнять удаление или обезличивание. Без карты происхождения запрос на удаление превращается в поиск по всему хранилищу с высоким риском пропустить копию.

Источники: Airflow docs, dbt docs, Wikipedia (data lineage) — ссылки в шапке.