Введение
Поток top-down даёт SwiftRide трассу от строки отчёта к кандидату CDE. Хорошо для регуляторной + финансовой защитимости. Плохо для теневых / операционных CDE — фичи pricing-движка, правила fraud-скоринга, обучающие наборы ML, join-ы атрибуции рекламы.
Поток bottom-up начинает с другого конца — технические метаданные + сигналы использования. Находит: какие колонки распространяются по платформе; которые питают много downstream-пайплайнов; которые запрашиваются многими пользователями / дашбордами / ML-задачами. Колонки с высоким влиянием — кандидаты CDE независимо от их видимости в отчётах.
ECB RDARR Guide (c) требует техническую lineage на уровне CDE. Поток bottom-up — это именно техническая lineage; используем его не только для валидации после top-down, но и для первоначального выявления.
Bottom-up — workflow из 4 шагов
Шаг 1 — Инвентаризация всех датасетов
Выход: структурированный список каждого датасета в дата-платформе.
Источники:
- INFORMATION_SCHEMA хранилища — каталог Snowflake / Databricks / BigQuery.
- OpenMetadata / Atlan ingestion — каталог уже инвентаризованных метаданных.
- dbt manifest.json — инвентарь source / model / seed.
- Листинги DAG Airflow / Dagster — инвентарь операционных пайплайнов.
Прагматика: типичная средняя дата-платформа — 5,000-20,000 таблиц / view / models. SwiftRide T0 ≈ 12,000 таблиц (БД бизнес-юнитов + хранилище + lakehouse).
Фильтровать рано:
- Отбросить внутренние staging-таблицы (
_tmp_*,stg_*гдеmaterialized=ephemeral). - Пропустить dev-окружения.
- Пропустить датасеты-тестовые-артефакты (
test_data_*). - Пропустить орфанные таблицы (нет downstream-потребителей, нет upstream, нет документации).
После фильтра: ~2,500 production-датасетов.
Шаг 2 — Трассировка lineage на уровне колонок
Цель: для каждого датасета идентифицировать, что в него втекает и куда вытекает — на уровне колонок.
Основной инструмент — спецификация OpenLineage.
Фасет lineage на уровне колонок OpenLineage (спецификация columnLineage) определяет:
DIRECT— выходная колонка получена напрямую из входной колонки (например,SELECT fare_total_usd FROM trip_records).INDIRECT— выход не содержит входное значение, но вход участвует в логике вывода (например,WHERE fare_total_usd > 0— fare_total_usd indirect lineage ко всем downstream-колонкам отфильтрованного запроса).masking— boolean-флаг: входное значение трансформировано до потока (хеширование, редакция, усечение).
Эмитируется интеграциями:
dbt—OpenLineageDbtIntegrationчитает manifest.json + catalog.json.airflow— операторы обёрнуты с lineage extractor.spark— listener захватывает план выполнения.snowflake— listener истории запросов.
Хранение: события отправляются в Marquez (проект LF AI & Data, референсный бэкенд) или в альтернативный бэкенд (Atlan, OpenMetadata, DataHub). UI Marquez показывает lineage на уровне колонок с бейджами DIRECT / INDIRECT.
Для SwiftRide T0: OpenLineage частично инструментирован (baseline M0.4). Топовое покрытие бизнес-юнитов:
- Пайплайн trip records — инструментирован (приоритет выручки).
- SwiftPay wallet — инструментирован (приоритет PCI-периметра).
- SwiftAds attribution — пробел (ещё не инструментирован).
- SwiftCapital model training — пробел.
Пробелы lineage являются first-class находками (см. антипаттерны M4.2).
Шаг 3 — Извлечение аналитики использования
На датасет / колонку считаем количественные сигналы использования:
| Сигнал | Источник | Интерпретация |
|---|---|---|
| Количество запросов (7д / 30д) | Snowflake ACCESS_HISTORY (Enterprise edition); история запросов Looker | Прокси частоты доступа |
| Уникальные пользователи / роли | Те же источники | Прокси широты потребления |
| Количество downstream-датасетов | OpenMetadata / Marquez | Структурное воздействие |
| Привязка к downstream BI | Метаданные Looker / Metabase | Видимость / влияние на отчётность |
| Downstream ML-фича | Метаданные Feast / Tecton | Воздействие на систему принятия решений |
| Свежесть last-modified | Скрейп каталога | Сигнал свежести (stale = брошенный кандидат) |
| External-pipeline consumer | Кросс-доменные ссылки dbt model | Кросс-org воздействие |
SNOWFLAKE.ACCOUNT_USAGE.ACCESS_HISTORY view — логи доступа на уровне колонок на запрос. Схема включает:
QUERY_IDQUERY_START_TIMEUSER_NAMEDIRECT_OBJECTS_ACCESSED— таблицы / view, запрошенные напрямую.BASE_OBJECTS_ACCESSED— базовые объекты (через view).OBJECTS_MODIFIED— цели записи.OBJECT_MODIFIED_BY_DDL— DDL изменения схемы.
Лаг: максимум 3ч задержки от выполнения запроса до записи в ACCESS_HISTORY. Retention: 1 год (Enterprise+).
Пример агрегации для топ-запрашиваемых кандидатов CDE:
SELECT
base.value:"objectName"::string AS table_fqn,
COUNT(DISTINCT query_id) AS query_count_30d,
COUNT(DISTINCT user_name) AS distinct_users_30d,
COUNT(DISTINCT date_trunc('day', query_start_time)) AS distinct_days_active
FROM snowflake.account_usage.access_history,
LATERAL FLATTEN(input => base_objects_accessed) base
WHERE query_start_time >= dateadd(day, -30, current_timestamp())
GROUP BY 1
ORDER BY query_count_30d DESC
LIMIT 200;Топ-200 — первичный пул кандидатов CDE.
OBJECT_DEPENDENCIES view дополняет — статические метаданные зависимости view → base table.
DataHub Cloud агрегирует статистику запросов на датасет через эмиттеры использования Snowflake / BigQuery / Databricks. Сущность UsageAggregation хранит:
total_query_counttotal_user_counttop_queries— пример SQL для контекста.top_columns— частота доступа к колонкам.
UI «Usage» tab на странице датасета — тепловая карта частоты доступа за последние 30 дней. Полезный прокси без необходимости прямого запроса ACCESS_HISTORY.
Шаг 4 — Распространение критичности + ранжирование кандидатов
Принцип: датасет downstream от известного CDE — автоматический кандидат. Дополнительно — датасеты с высокими сигналами использования — кандидаты.
Правило распространения: если колонка C ∈ Table T1 → используется в выводе колонки C’ ∈ Table T2, и T1 в реестре CDE — T2 автоматически кандидат. Распространение рекурсивно до отсечки трансформации (mask / agg-only-output / агрегация, рвущая прямую связь).
Сигналы ранжирования для новых кандидатов (не появившихся через распространение):
candidate_score = w1 × query_count_norm
+ w2 × distinct_users_norm
+ w3 × downstream_dataset_count_norm
+ w4 × downstream_bi_binding (boolean)
+ w5 × downstream_ml_feature (boolean)
+ w6 × cross_org_pipeline_count_norm
Веса калибруются под организацию. Дефолты — w1=0.20, w2=0.15, w3=0.30, w4=0.15, w5=0.15, w6=0.05.
Выход: ранжированный список. Топ-N → ревью на кандидатуру CDE. Низ — отложить или пометить not_cde_low_usage.
Критично: ранжирование ≠ вердикт. Ранжирование — вход для финального скоринга критичности (M1.3-M1.4). Горячий дашборд для маркетинговой команды может быть высоко оценён в ранжировании, но критерий материальности (M1.2) отклонит в финальном скоринге.
Inventory → column lineage → usage signals → ranked candidates. Каждая нода — стадия со входами / выходами. Тултипы раскрывают тулинг на стадию.
12K → 2.5K после фильтраШаг 1 — инвентаризация всех датасетов через INFORMATION_SCHEMA + OpenMetadata + dbt manifest.json + листинги DAG Airflow. Фильтр staging / test / orphan. SwiftRide T0: 12K → 2.5K production.
Фасеты OpenLineageШаг 2 — lineage на уровне колонок через OpenLineage 1.46 (фасеты DIRECT / INDIRECT / masking). Бэкенд Marquez / OpenMetadata / DataHub. Пробелы lineage = first-class находки.
Запрос · пользователи · downstreamШаг 3 — извлечение аналитики использования. Snowflake ACCESS_HISTORY — количество запросов / пользователей. Количество downstream-потребителей. Boolean привязки BI. Boolean ML-фичи.
Downstream от CDEШаг 4a — распространение критичности. Датасет downstream от известного CDE = автоматический кандидат. Рекурсивная трассировка через рёбра DIRECT lineage.
Взвешенный скор → ревьюШаг 4b — ранжированный список кандидатов по взвешенному скору сигналов. Топ-N → ревью на кандидатуру CDE. Низ помечен not_cde_low_usage. Ранжирование ≠ вердикт.
Валидированные кандидатыВыход — набор кандидатов для валидации со стейкхолдерами (M4.4) и финального скоринга критичности (M1.3-M1.4). Кросс-валидация с находками top-down (M4.2).
Что bottom-up находит лучше top-down
Операционные данные решений:
- Feature store pricing-движка (
fct_pricing_features_v3) — питает реальный pricing каждую секунду; downstream BI = revenue-дашборд. Top-down от строки выручки в конце концов трассирует, но bottom-up сразу выявит через высокий downstream-count + флаг ML-фичи. - Таблица правил fraud-скоринга (
scd_fraud_rules) — slowly-changing dimension с версионированием; запрашивается по каждой транзакции. Операционный tier-1. - Фичи алгоритма матчинга водителей (
fct_matching_features) — питает сервис матчинга; не в финансовых отчётах, но в периметре прозрачности рекомендаций DSA.
Теневые / недокументированные пайплайны:
- Датасеты с высоким использованием, но без задокументированного владельца: bottom-up флагирует. Top-down от отчётов (потенциально) пропускает, если пайплайн обходит формальную lineage.
- Excel / ручные импорт-датасеты, зарегистрированные в Snowflake — bottom-up видит частоту запросов; top-down может не выявить, если ручные журнальные записи уже категоризированы отдельно.
Кросс-доменные зависимости:
- Таблицы reference data (курсы валют, коды стран, версии регуляторных списков) — bottom-up видит через широкий downstream-count.
Что bottom-up пропускает
Низкочастотные стратегические данные:
- Выходы квартальных регуляторных сдач (Pillar 3, агрегаты AML SAR). Количество запросов низкое (запускается квартально), но материально на запуск.
- Ежегодные отчётные агрегаты.
- Ежегодные таблицы disclosures.
Новые / нетронутые данные:
- Датасеты только что запущенного продукта — короткая история запросов, сигнал слабый.
- Митигация: комбинировать с датой регистрации / инструментации lineage; недавно созданные датасеты — отложить ранжирование, применить top-down + интервью со стейкхолдерами.
Датасеты под маской / агрегацией, рвущей lineage:
- Выходы ML-моделей — downstream-пайплайны, агрегирующие много фич. Lineage на уровне колонок останавливается. Митигация: реестр моделей — отдельный трек метаданных.
Риски, специфичные для bottom-up
”Hot but not critical”
Симптом: ранжирование находит 50 маркетинговых аналитических таблиц в топ-100; кандидатуру CDE для них + поднимается тревога.
Почему плохо: разбавляет реестр CDE нематериальными элементами. Доверие к программе страдает.
Исправление: ранжирование — предложение, не вердикт. Финальный скоринг по M1.3-M1.4 — применять на кандидата. Отклонять элементы с низкой материальностью.
”Quiet but critical”
Симптом: таблица выхода квартальной регуляторной сдачи — количество запросов 8 за 30 дней. Ранжируется низко. Но — критично с регуляторной точки зрения.
Исправление: распространение (downstream от известного CDE = кандидат) компенсирует. Дополнительно — domain-aware фильтр: выходы регуляторных сдач помечаются как domain-priority независимо от использования.
”Пробел OpenLineage = молчаливый пропуск”
Симптом: пайплайн SwiftAds attribution не инструментирован. Bottom-up не поднимает кандидата; трасса top-down останавливается на границе; никто не выявляет. Big 4 находит при инциденте.
Исправление: пробел lineage = first-class находка. Ручное ревью для неинструментированных пайплайнов; задача инструментации в плане. Каденс обновления M4.7 пересматривает.
”Устаревший кандидат CDE”
Симптом: датасет активно запрашивался 2 года назад; сейчас upstream декомиссионирован, но downstream-потребители продолжают запросы. Ранжирование всплывает, но датасет устарел.
Исправление: включить сигналы last_modified + last_pipeline_run; deprecate устаревшие кандидаты.
”Слепое пятно кросс-регионального пайплайна”
Симптом: данные пайплайна ЕС не в US Snowflake-аккаунте; bottom-up sweep против US-аккаунта пропускает CDE ЕС.
Исправление: прогонять каталог каждого региона независимо; сверять глобально.
Bottom-up sweep SwiftRide — поставка фазы 2
T+1M → T+2M:
- Инвентарь: 12,043 датасета → 2,489 production-grade после фильтра.
- Покрытие lineage на уровне колонок: ~62% (пробелы в SwiftAds, SwiftCapital training, некоторые legacy SwiftPay).
- Сигналы использования извлечены: топ-500 таблиц.
- Применено ранжирование: ~50 кандидатов ≥ порога.
- Распространение критичности: 18 датасетов downstream от top-down CDE (фаза 1 M4.2) — автоматическая кандидатура.
- Дедупликация против фазы 1 (top-down M4.2): 12 уникальных новых bottom-up кандидатов. Кумулятивно ~42-45 уникальных кандидатов (top-down + bottom-up).
- Задокументированы пробелы lineage: 8 высокоприоритетных (задачи инструментации T+3M).
- Отчёт согласования: расхождения между находками top-down + bottom-up.
Итоги
- Bottom-up — 4 шага: инвентаризация всех датасетов → lineage на уровне колонок → аналитика использования → распространение + ранжирование.
- OpenLineage 1.46 фасет lineage на уровне колонок — DIRECT / INDIRECT / masking — основной примитив. Marquez — референсный бэкенд.
- Snowflake ACCESS_HISTORY — логи доступа на уровне колонок; лаг 3ч; retention 1 год Enterprise+. Вход для ранжирования топ-N.
- DataHub UsageAggregation — альтернатива для статистики запросов без custom SQL.
- Распространение критичности — downstream от известного CDE = автоматический кандидат (рекурсивно).
- Ранжирование ≠ вердикт — вход для финального скоринга критичности (M1.3-M1.4); применить фреймворк материальности.
- Сильные стороны bottom-up: операционные данные решений, теневые пайплайны, кросс-доменные зависимости.
- Слабые стороны bottom-up: низкочастотные стратегические данные, новые нетронутые данные, маскирование / агрегация, рвущая lineage.
- Риски: hot-but-not-critical; quiet-but-critical; пробел OpenLineage = молчаливый пропуск; устаревшие кандидаты; кросс-региональные слепые пятна.
- SwiftRide T+1M-T+2M: 50 ранжированных кандидатов; 18 распространены из top-down CDE; 12 уникальных новых кандидатов; 8 пробелов lineage задокументировано.
- Следующий урок (M4.4): интервью со стейкхолдерами — методика вопросников + RACI + 3 скрипта (бизнес-владелец / инженер / аудитор) + разрешение конфликтов.