Привет, меня зовут Юля, я дата-инженер в департаменте аналитических решений ЮMoney. Мы разрабатываем и поддерживаем ETL(ELT)-процессы загрузки данных для BI-продуктов компании: отчётов, дашбордов, витрин, API и других.

В этой статье поделюсь, как мы разрабатывали MVP для построения data lineage системы и к каким выводам пришли, — так вы сможете адаптировать подход под свои процессы.

Проблема, которая привела нас к разработке MVP, заключается в том, что в начале работы над большинством задач требуется подготовительная аналитика: восстановить путь происхождения данных, чтобы понимать, какие ETL(ELT)-процессы будут затронуты и на что повлияют изменения. Это увеличивает время выполнения задачи. Но, что ещё существеннее, процесс достаточно рутинный: каждый раз необходимо проводить статический анализ кода и изучать документацию (при её наличии). Мы решили автоматизировать эту работу, чтобы иметь под рукой инструмент для построения пути данных по точкам их обработки и применения, — то есть создать data lineage систему.

Подходы к построению data lineage систем

Data lineage системы можно строить:

  1. Вручную, через явное указание зависимостей в данных.

  2. Через описание метаданных (например, в yml-файлах, jinja-шаблонах), которые затем можно загрузить, например, в dbt и использовать для визуализации движения данных.

  3. Автоматически, путём разбора метаданных из кода и их визуализации.

Первый вариант возможен для реализации, если требуется построить data lineage разово или для ограниченного набора бизнес-процессов, так как при любых дальнейших изменениях в ETL(ELT)-процессах загрузки и использования данных потребуется вручную актуализировать полученный data lineage.

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

Наш стек и реализация

Мы не хотели тратить больше одного квартала на разработку MVP, поэтому выбрали один из основных кейсов движения данных от источника до пользовательского продукта: получение сырых данных из Kafka организация хранения в таблицах stage-слоя упорядочивание и преобразование в таблицах DWH сбор витрин для пользователей.

MVP реализовали на .NET 8. Парсинг кодовой базы решили проводить с использованием библиотеки DacFx (подробнее о преимуществах парсера — в статье коллеги «Какой парсер для автоматизации ревью кода лучше — DacFx или ANTLR»).

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

В начале разработки мы подготовили метамодель хранения данных: выделили основные сущности типа data (Topic — топик Kafka, Table — таблица базы данных, DataMart — витрина данных) и сущности типа transport для определения связей между ними (KafkaService — сервис разбора данных из топика Kafka, Procedure — хранимая процедура, участвующая в ETL(ELT)-процессе, и так далее).

На первой итерации мы выделили основные типы связей между объектами: EXEC, USE и другие, полагая, что это облегчит написание Cypher-запросов. Однако в процессе разработки поняли, что для нашей реализации достаточно только направления связи (пример одного из Cypher-запросов можно будет увидеть в разделе ниже).

На этапе MVP результаты предполагались к использованию только дата-инженерами нашего департамента, поэтому для визуализации data lineage мы использовали встроенный Neo4j browser, позволяющий отображать конкретные кейсы движения данных через выполнение Сypher-запросов.

Схема работы MVP приведена на рисунке ниже.

Результат работы

Так выглядит один из примеров получившегося data lineage (скриншот из Neo4j browser): на нём можно проследить путь от источника — топика Kafka — до витрин, использующих данные этого топика. Стрелки показывают направление движения данных.

В процессе работы с MVP со стороны пользователя мы поняли, что необходим набор эффективных Cypher-запросов. В частности, полезны встроенные функции, такие как shortestPath — для получения минимальной последовательности рёбер между двумя узлами и allShortestPaths — для получения всех минимальных последовательностей рёбер между двумя узлами.

Для построения data lineage, как на рисунке выше, использовался следующий Cypher-запрос:

Для получения кратчайшего пути нужно указать название топика Kafka (сущность Topic, атрибут name), в квадратных скобках — количество ребёр в цепочке (в нашем случае — от 1 без верхнего ограничения), направление движения данных (направление стрелки) и конечный объект (витрина данных — сущность DataMart).

В процессе разработки MVPмы тестировали сервис на реальных кейсах заказчиков. Например, запросы вида «какой топик/топики является источником для витрины данных или отчёта» решаются за несколько минут: получить итоговый datalineage и отсечь связи, не относящиеся к задаче. Без MVPответ требует поиск в кодовой базе или документации, что занимает от получаса до нескольких часов — в зависимости от сложности задействованных ETL(ELT)-процессов.

К чему пришли и что планируем делать дальше

На текущей итерации мы подготовили локальное решение, позволяющее каждому дата-инженеру департамента построить data lineage для предметной области своей команды. При положительной обратной связи планируем доработать сервис, развернуть его для общего пользования и настроить триггеры на пулл-реквесты в DWH-репозиториях для своевременного отслеживания изменений в data lineage процессах.

Рекомендуем внедрение data lineage компаниям, где уже реализована или внедряется система data governance, поскольку data lineage является её составной частью.


Поделитесь опытом: реализовывали ли вы подобные системы? С какими проблемами сталкивались при разработке и используете ли эти системы в повседневной работе?

Комментарии (0)