Как мы внедрили свою модель хранения данных — highly Normalized hybrid Model. Доклад Яндекса

Общепринятый и проверенный временем подход к построению Data Warehouse (DWH) — это схема «Звезда» или «Снежинка». Такой подход каноничен, фундаментален, вотрфоллен и совсем не отвечает той гибкости, к которой призывает Agile. Чтобы сделать структуру DWH гибкой, существуют современные подходы к проектированию: Data Vault и Anchor modeling — похожие и разные одновременно. Задавшись вопросом, какую из двух методологий выбрать, мы в Яндекс Go пришли к неожиданному ответу: выбирать надо не между подходами, а лучшее из двух подходов.

Темы доклада, который вместе со мной прочитал Николай Гребенщиков:
— DV и AM: в чем разница и где точки соприкосновения
— Гибридный подход к построению хранилища
— Сильные и слабые стороны этого подхода
— Примеры кода
— Дальнейший вектор развития hNhM

— Меня зовут Евгений Ермаков, я руководитель Data Warehouse в Яндекс Go.
Я расскажу историю о том, как два руководителя объединились и сделали нечто крутое — как минимум, по мнению этих двух руководителей. Расскажу про наш подход к хранению данных в детальном слое. Мы его называем highly Normalized hybrid Model. Надеюсь, что корректно произнес по-английски, я тренировался.

Мы это сокращаем до hNhM — не пугайтесь, если услышите эту странную аббревиатуру. Можно еще «гибридная модель» или «двухстульная модель». А почему двухcтульная, я обязательно расскажу на примере одного мема.

-mjqqfw1ezem03ovvabys3g3ybc.jpeg

Рассказ у нас будет достаточно долгий, из двух глав. Первая глава будет моя — я расскажу, как мы вообще к этому пришли. Она, наверное, будет для тех, кто сведущ в этой теме, или послужит повторением того, что вы уже знаете.

Также я расскажу про архитектуру хранилища Яндекс Go в целом, вместе с детальным слоем, где как раз эта модель и применяется. Потом сравню Data Vault и якорное моделирование так, как мы у себя их сравнивали, и объясню, почему мы из этого сравнения сделали вывод, что нужно создавать нечто свое. И расскажу базисные основы про hNhM.

t2xr1vya33qzusostfq79oyqjdu.jpeg

А во второй главе я передам слово Коле.

Николай Гребенщиков:
— Я расскажу о нашем фреймворке, который позволяет нам описывать сущности и загружать данные. Покажу, как мы с ним работаем, как загружаем используем и строим витрины над нашим детальным слоем.

— В конце мы подведем итоги, самое главное, что можно из этого доклада почерпнуть. посмотрим, куда мы пришли, что сделали и как это можно переиспользовать.

skaddphkmgfauzltvzmymn2gbgw.jpeg

Итак, архитектура Data Warehouse (DWH) в Яндекс Go. Расскажу об архитектуре слоев данных, какая она у нас, какие инструменты хранения и обработки информации есть, и покажу место детального слоя во всей этой архитектуре.

k6c0r7sxtikx7wr7r8v1sd5eiw8.jpeg

По моему мнению, архитектура слоев данных в нашем хранилище максимально классическая. Мы шли от глаголов действий над данными, которые происходят с хранилищами. Что мы делаем с данными?

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

Потом мы предоставляем эти данные для анализа, непосредственно анализируем и все. Классика.

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

0g36yj075q7vb2vj51ydwauysqa.jpeg

Дальше мы все это стандартизируем в операционном слое. Здесь мы храним операционные данные из источника без истории. Возможно, с какой-то ротацией, например год или месяц, зависит от источника и его объема.

Задача этого слоя — сформировать набор сущностей источника и предоставить стандартный интерфейс доступа к этим данным, вне зависимости от особенностей источника. Все примерно в стандартном виде.

Дальше детальный слой. Ядро хранилища. Здесь мы храним детальную историю изменений и консолидируем данные между всеми источниками.

75ihkqvkbw6wavqqamoutrsq14o.jpeg

На базе этого детального слоя есть слой витрин Common Data Marts.

zewggwx6c1ckdzwnfdr5iw6-lmc.jpeg

Здесь мы уже формируем плоские, удобные для аналитиков витрины и оптимизируем доступ на чтение.

wnxuigrreafcspinwpybm_x93q0.jpeg

В слое отчетов мы храним отчетные срезы в контексте без потребителя, агрегаты, нечто более понятное для потребителя.

hub3eideitvzj7qtdsknuq032li.jpeg

В итоге — классика, все по слоям, от RAW до REP. Данные протекают в хранилище, все как завещали Кимбалл и Инмон в своих подходах.

Если это рассматривать прямо по системам, то для того, чтобы захватывать данные, у нас есть сервис репликации данных. Он забирает инкременты и снепшоты из источников самых разных типов, которые есть в Яндексе. И преобразовывает эти данные к устойчивому формату.

tpoed24kcjmf684we6hvvunlbug.jpeg

RAW, ODS — это такой Data Lake. Здесь у нас полуструктурированные данные, каркас MapReduce и всевозможные внутренние аналоги экосистемы Hadoop.

Центр хранилища — это непосредственно Data Warehouse. Здесь у нас слои ODS, DDS, CDM.

mb6dmxgysvj9lrrkdl5xat_svv4.jpeg

Основные цели — давать ответ на всевозможные ad-hoc-запросы наших аналитиков, выдерживать большое количество Join и достаточно малое время отклика на всевозможные вопросы.

И витрины. Помимо того, что они служат Data Warehouse, мы еще отгружаем их содержимое в системы анализа и визуализации данных. Это кубы данных, отчеты, дашборды, Tableau.

iph0-tb1awu2nboh5guei4beplo.jpeg

Если мы эти слои разложим по системам, то получится приблизительно такая картина.

То есть RAW, ODS и части CDM-слоя на супербольших данных — это у нас Data Lake.

h10mifd3qj2ehs78ejbmqng60t0.jpeg

Маленькая ремарка: в Яндексе много внутренних инструментов, которые мы делаем сами. У нас есть своя собственная платформа, есть такие внутренние инструменты, как YT. Можно проводить аналоги: YT — это как Hadoop. И в принципе, есть всевозможные аналоги Hadoop-стека.

На Greenplum у нас находятся часть слоя ODS, детальный слой и витрины. Построенные в Greenplum витрины мы затем отгружаем в MS SSAS или ClickHouse для ряда пользователей. Некоторым удобно пользоваться кубами данных, некоторым — широкимb плоскими таблицами, и ClickHouse здесь прямо идеален.

Часть витрин доступно для биосистем, или мы делаем из них агрегаты, доступные для нашего BI. BI у нас — это Tableau.

Ремарка: я прямо не рассказываю про наш инструментарий, не рассказываю про те возможности платформы, которые у нас есть. Очень советую посмотреть доклад Владимира Верстова, это руководитель разработки нашей платформы, где он подробно расскажет, зачем наша платформа управления данными создавалась, какие задачи она решает и что вообще делает.

Смотреть доклад Владимира

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

Если посмотреть на детальный слой, он не зря находится в самом центре хранилища, потому что это ядро, сердце, ключевое для построения всей доменной модели хранилища.

fha88vgoqcafwefeugcwcqeu7zi.jpeg

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

Два важных пункта. Детальный слой должен быть устойчив к изменению в бизнесе. Это достаточно сложно: допустим, мы изменили кардинальные связи или добавили новые сущности. Или у нас полностью изменился подход к бизнесу.

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

Когда мы начали проектировать детальный слой, то провели анализ —, а какие подходы к построении детального слоя вообще есть? Первое, что приходит на ум, — это когда нет «никакого» детального слоя или подхода.

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

А подход, который называется «никакого подхода», — это когда мы просто сваливаем данные в кучку и потом пытаемся их них что-то извлечь. Если огрублять, это что-то вроде болота данных.

К сожалению, такой подход тоже имеет право на жизнь только потому, что он часто встречается. Так-то он, конечно, не имеет права на жизнь. Тем не менее, тут у нас денормализация. Можно использовать без подготовки в том плане, что легко селектить. Однако здесь нет устойчивости к изменениям, при любых изменениях в источнике придется все это перестраивать.

ezteokc3-rcftxlzfc93b2qi2iu.jpeg

Пойдем дальше. Следующий подход — классическая звезда и снежинка. Нормализация до третьей нормальной формы, то, что описывал у себя Билл Инмон. Это можно использовать с минимальной подготовкой — нужно понимать, что такое первичный ключ, внешний ключ, join-таблички, SCD2, если мы говорим про измерения. И понимать, какие SCD вообще существуют.

Это может быть неудобно перестраивать при изменении кардинальности. Например, есть клиент и заказ. У одного клиента может быть много заказов, но у одного заказа только один клиент. Бизнес поменялся, у одного заказа теперь может быть несколько клиентов, и клиенты могут делить между собой заказ, как это, например, реализовано в такси. Перестраивать все это крайне больно.

При этом минимальное дублирование информации, если мы используем SCD. И какое-то приемлемое количество join. Если аналитики работают с SQL, они должны уметь работать и с этим.

Следующие походы — Data Vault и Anchor modeling. Почему я их вывел одновременно? Потому что они предлагают, на самом деле, нечто очень похожее. Это достаточно строгая нормализация, их сложно использовать без подготовки, без понимания, какие таблицы и какие правила они накладывают.

vpbjsxc65m2gxqgsmqjd1gd9uw4.jpeg

Обе методологии обещают, что их не надо перестраивать. Для Data Vault это работает с ограничениями, я дальше проговорю, какими. Здесь ультрабольшое количество join. При этом обе методологии относительно современны и обещают гибкость.

Посмотрим на эксплуатацию. Все, что справа, — Data Vault и якорное моделирование — достаточно сложно эксплуатировать из-за большого количества join. Чем больше join, тем сложнее писать SQL-запросы и в целом получать отсюда информацию. При этом проще вносить изменения в модель. Во всяком случае, обе методологии это обещают.

И наоборот, если у нас никакого подхода нет и мы всё вкладываем в плоскую табличку или нормализуем, то эксплуатировать проще. join или вообще нет, или их приемлемо малое количество. Но при этом вносить изменения, перестраивать сложно.

Когда мы начали смотреть на Data Vault и якорное моделирование, они показались нам крайне близкими и мы решили сравнить их между собой.

gsuvtesk3bvhnlorqcs7ov5grwu.jpeg

Здесь я перехожу ко второй части своей главы — к сравнению Data Vault и якорного моделирования, плюсам, минусам и итогу — что из них выбрать.

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

Сперва стоит спрогнозировать требования, а потом подумать, согласовать, подумать еще. Я уверен, что все, кто работал с классическими DWH, которые построены не по Data Vault или по якорю, понимают, что DWH — это не быстро.

Но здесь классический дэвэхашник сталкивается с проблемой: заказчик не знает, чего хочет. Готов смотреть на результат, а потом уточнять, что ему хочется. Его желания постоянно меняются.

И вообще, у нас Agile, мы гибкие, давайте все переделывать максимально быстро. Желательно, завтра. Примерно так выглядит классический дэвэхашник, когда попадает в Agile-среду, в которой невозможно использовать Waterfall.

Логичные вопросы: откуда родились методологии Data Vault и якорь; может ли DWH быть agile; можно ли подходить к разработке хранилища гибко?

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

hzyftuavnvhx0cokbn6bakyf1z0.jpeg

Взамен они обещают уменьшить постоянное дублирование данных в SCD2, если у нас меняется только один атрибут. Те, кто работают с SCD2, знают, что если у нас большое измерение, много атрибутов, а меняется только один, то нам приходится снова эту строчку вставлять. И это больно. Обе модели обещают избавить от деструктивных изменений, только расширять модель и позволить дорабатывать хранилище легко и быстро. Мистика для любого хранилищного аксакала.

eg0ev6hiqxq2l8olduylhzqjnay.jpeg

Кратко пройдусь по каждой из методологий, чтобы потом их можно было сравнить.

Data Vault вводит и регламентирует несколько основных тип таблиц. Ключевые — это Hub, Link и Satellite, дальше я буду о них говорить. Hub хранит сущности, Link обеспечивает связь между хабами, Satellite предоставляет атрибуты и описания Data Vault.

Data Vault 2.0 я не буду касаться. Есть еще специальные таблицы типа bridge и point-in-time. Они упрощают или соединение данных через несколько связей, или получение информации из сателлитов с разной частотой обновления. Это скорее расширяющие, упрощающие модель сущности. Ключевые таблицы — это все-таки Hub, Link и Satellite.

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

fmqlpr_nyeyh86-024zludmjyka.jpeg

Link или связь — это физическое представление отношения между сущностями. При этом они всегда реализованы в виде таблиц «многие-ко-многим», в виде отдельных таблиц. Атрибуты Link включают в себя суррогатный ключ Link, ключи хабов в зависимости от того, какие хабы связаны через эту связь, и техническую информацию — временную отметку даты загрузки и код источника.

Satellite или сателлит — это описательная информация хаба, обычно с историзмом по SCD2. Здесь есть информация о ключе связи или хаба, в зависимости от описательных характеристик того, что находится в этом сателлите, сама информация и технические записи: SCD2, временная отметка даты загрузки, код источника данных.

Если на это посмотреть с точки зрения третьей нормальной формы, то есть вот такая неплохая картинка из презентации самого автора Data Vault:

ijn7zgyms7zc4aeemffkuet8pek.jpeg
Ссылка со слайда

Посмотрим на третью нормальную форму. Видно, что бизнес-ключи мигрируют в хабы. Все внешние ключи мигрируют и фактически являются связями. А все описательное, все наши поля, которые несут какой-то смысл, уходят в сателлиты. Сателлитов может быть несколько. Нет явных правил, как правильно разбить атрибуты на сателлит. Есть разные подходы: можно бить по частоте изменений, по источнику, по чтению — это такой творческий момент в Data Vault.

3wrufrzb0cjg9whnuqns5-urf6u.jpeg

Если мы посмотрим на якорное моделирование, то я бы его сформулировал как такую крайнюю форму Data Vault, когда у нас правила еще строже и нормализация еще выше.

У этой методологии есть четыре основных типа таблиц — якорь, атрибут, связь и узел. Про узел я не буду подробно рассказывать, фактически это словарь ключ-значение. А про якорь, атрибут и связь сейчас коротко расскажу.

Якорь — фактический аналог хаба с важным отличием: здесь нет бизнес-ключей, есть только суррогатный ключ и временная отметка даты загрузки, техническая информация. Все бизнес-ключи фактически являются атрибутами и хранятся в таблицах атрибутов.

1dwtyym7kjcx4x5472tcg-zohbs.jpeg

Tie — связь «многих ко многим», один в один как в Data Vault. Внешние таблицы — это принципиальный момент, даже если кардинальность связи другая. Но в якорном моделировании есть отличие — у связи принципиально не может быть атрибутов.

Сами атрибуты, как и сателлиты, хранят описательную информацию нашей сущности. Важное отличие: это шестая нормальная форма, один атрибут — одна таблица. Такое кажется, с одной стороны, странным, а с другой, расширение атрибутивного состава сущности проходит легко и просто. Мы добавляем новые таблицы, ничего не удаляем, изумительно и прекрасно.

Но расплачиваться за это приходится дорого. Даже очень простая схема, которая загружена на слайде, превращается в гигантское, просто неимоверное количество таблиц.

Скриншот взят с самого сайта якорного моделирования. Понятно, что это не само физическое представление таблиц. Все таблицы, которые с двойным кружком, историзируемые. Все остальное — это якоря и связи.

85z3d-xlwv02ochibtv55jejsk0.jpeg

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

ky8t5vlfcobwnqa1jr0u6jizqbi.jpeg

Внешние ключи находятся в наших связях.

nzi0ecrhobzpkcnt4h3vq26_e2e.jpeg
Ссылка со слайдов

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

Возникает вопрос: нельзя ли хоть как-нибудь прохачить систему и навесить атрибут на связь? Можно через словарь. Но это именно что словарик, некий типизатор связи. Ничего более сложного на связь в якорной модели навесить нельзя.

Посмотрим на стандартный тест TPC-H. Я уверен, что многие из вас знают, что это такое, но кратко напомню: это стандартный тест для проверки аналитических хранилищ, внизу на слайде есть ссылка на одну из его версий.

aofrgyl8r__6zpzbyka1woxcpts.jpeg
Ссылка со слайда

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

Если мы эту схему преобразуем в Data Vault, то видно, насколько больше таблиц становится, появляются отдельные хабы, отдельные Link. Причем Link сделаны в виде таблиц «многие-ко-многим».

yi1iw0wxs0ssta4gqli4joxawte.jpeg
Ссылка со слайда

У нас вешаются сателлиты — как на Link, так и на отдельные хабы. И в целом, таблица становится больше.

Если мы это конвертируем в якорную модель, получится нечто подобное.

kg28huljvyjmegoiogbqwjbaupu.jpeg

Честно говоря, на этом слайде есть небольшое лукавство в том смысле, что я не нашел якорной модели в TPC-H, хотя пытался найти. Взял просто абстрактную схему с сайта якорного моделирования. Но, тем не менее, таблиц должно быть примерно столько, если не больше.

В чем же схожести и различия, если их в лоб сравнивать?

dlgrofe-yqurn52yjxlwpgr-ztg.jpeg

И в Data Vault, и в якоре создается специальная таблица на сущность. В Data Vault это Hub, в якоре это якорь. Разница в том, что в хабе есть бизнес-ключ, а в якоре бизнес-ключ — это атрибут.

В Data Vault атрибуты группируются в таблицы-сателлиты. В якоре все строже: один атрибут — одна таблица, шестая нормальная форма, все раскладываем на отдельные кубики-элементы.

Связи через отдельные таблицы — и там и там, физическая реализация — «многие-ко-многим». Но в якоре нельзя навешивать никакие атрибуты на связи. Если и возникает такое желание, значит, скорее всего, нам нужно выделить под это какую-нибудь сущность.

И есть специальные таблицы, в Data Vault — point in time и bridge, в якоре — knot.

Когда мы вот так, в лоб, их сравнили, ощущение было — что выбрать? В чем-то лучше якорь, в чем-то — Data Vault. У каждого достаточно цельная методология. Якорь построже, но, с другой стороны, возникает меньше вопросов и больше пространства для автоматизации.

aisp6tchcz6zpzyr84dgrnyan1m.jpeg
В общем, как-то так. Яндекс славится тем, что создает свои инструменты. Почему бы нам не создать свою модель?

Идея простая. Надо выбирать не между методологиями, а лучшее из каждой методологии и уметь применять это лучшее в каждом конкретном случае.

87sfm97loq1ib3_huk-dx9pjj2i.jpeg

Из этой идеи и родилась наша гибридная модель highly Normalized hybrid Model, hNhM. Здесь я кратко расскажу ключевые идеи модели. (…)

__zozzhevwyw4x4fuhlqgwweje4.jpeg

Ключевая идея — выбирать оптимальный формат хранения. Мы не ограничиваем себя ни Data Vault, ни строгостью якоря. Но при этом позволяем выбрать либо одно, либо другое. А если мы позволяем это выбрать, то с точки зрения методологии классно было бы разделить логическое и физическое моделирование.

Еще есть требование, которое мы сами себе ставили: параллельная загрузка из разных источников, идемпотентность при повторной загрузке тех же данных. Стандартная для Data Vault и якоря устойчивость к изменению в бизнесе, модульность и масштабируемость.

И удобство построения витрин. Потому что да, таблиц очень много, есть большой риск написать не оптимально. Это даже не то чтобы риск. Просто вокруг тебя раскиданы мины. Очень хочется дать инструментарий, чтобы со всем этим было удобно работать.

Если пойти по этим идеям, посмотреть очень верхнеуровнево, то мы это представляли так.

usc5vcd06ueulydjtzvgydswjb8.jpeg

У нас есть слои, про которые я рассказывал, RAW. ODS — это наш Data Lake. В RAW мы захватили данные, они лежат как есть. В ODS мы их чуть почистили, но это операционные данные, без истории. В детальном слое мы фактически разложили это все на маленькие кубики-сущности. С точки зрения логического проектирования это сущности-связи между ними. С точки зрения физического хранения на нашем Greenplum это скрыто с точки зрения использования.

Дальше мы на базе DDS, где все наши данные уже слились, строим витрины — и плоские, и кубы, как нам хочется. Делаем из этого срезы. В общем, DDS — это такой конструктор Lego.

То есть мы сначала разбираем все на кубики, а потом из этих кубиков собираем что-то красивое. Во всяком случае, мы себе так это рисовали на старте. К концу доклада вы сможете понять, получилось у нас сделать это так, как мы это изначально планировали, или нет.

Про разделение логического и физического уровня. Мы хотели на старте их разделить явным образом.

Логический уровень — это всем известные ER-диаграммы. Уверен, что все, кто работает с данными, про ER-диаграммы знает. Здесь есть сущности и их ключи, связи между сущности и атрибутивный состав сущностей. Мы еще добавили необходимость их историзации, но это как дополнительная информация к атрибутам.

Логический уровень — когнитивно сложная часть проектирования. Он не зависит от СУБД в общем виде и достаточно сложен. Трудно выделить сущности и домены в бизнесе, особенно если ты его не знаешь так, как основатели этого бизнеса.

tyh00caq1ijpddjzuxy-zfp0yae.jpeg

Физический уровень — это скрипты DDL. Здесь выполняется партицирование сущностей, объединение атрибутов в группы, дистрибьюция в системах MPP. И индексы для ускорения запросов. Все перечисленное мы хотели скрыть. Во-первых, оно зависит от СУБД и технических ограничений, которые у нас есть. Во-вторых, нам хотелось сделать так, чтобы этот физический уровень был невидим, чтобы мы могли переключаться между Data Vault и якорем, если захотим.

merzf3l_viphoq1g4kzjpy-_e04.jpeg

Разделяя так логический и физический уровень, мы фактически делим задачи между нашими ролями. У нас есть две роли:

  • Партнер по данным, Data Partner. Мы так переименовали Data steward. Да, слово steward имеет здравое значение в переводе: распорядитель чего-то чужого, а данные в этом смысле чужие. Но все равно «партнер по данным» звучит гораздо лучше.

    Партнер по данным на логическом уровне должен ответить на вопрос концептуальной модели: какие вообще направления бизнеса и взаимосвязи между ними у нас есть, как часто будут меняться атрибуты. И из этого построить логическую модель, прямо по классике.

  • И инженер данных, здесь все классически. Он отвечает на вопросы физической модели: как хранить атрибуты, нужны ли партиции, нужно ли закрытие SCD2. И обеспечивает сам расчет данных по инкременту, а также пересчет истории, то есть фактически ETL-процесс.

Внизу есть платформа, это наши разработчики ядра. Они каждый день задают себе один и тот же вопрос: как сделать инструментарий по работе с данными удобным, чтобы наши партнеры по данным и инженеры данных работали лучше?

ao_dvpkjy-jxle7u-kegkylragy.jpeg

В итоге, базируясь на ER-диаграммах, мы используем сущность и связь. Сущность — базовый кубик любого описания домена. Здесь, на логическом уровне, мы хотели сделать так, чтобы сущности описывались наименованием и комментарием; именем сущности и его описанием; бизнес-ключом, который обязателен для любой сущности, чтобы понимать, что его определяет; и каким-то набором атрибутов.

Сам атрибут описывается наименованием и комментарием, типом и необходимостью хранить историю. Мы можем хотеть или не хотеть хранить историю, это нормальный вопрос на логическом уровне.

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

Атрибут — это таблица. Она содержит информацию об одном атрибуте, может содержать историю, а может не содержать. Group — это группа атрибутов, как сателлит в Data Vault. Она может содержать информацию о нескольких атрибутах. Важное ограничение на уровне модели: все атрибуты должны приходить в эту группу сателлита из нового источника и иметь один тип историзма.

xz0ambfskinsa2qfpkgo1x3zdzw.jpeg

Связь. На уровне ER-диаграммы понятно, что это такое. С точки зрения логического уровня это список связанных сущностей и кардинальность связи. Здесь мы пошли по жесткой модели якоря и не позволили хранить у связи никаких атрибутов. Если хочется повесить на связь атрибут, то для этого должна быть отдельная сущность.

На физическом уровне это абсолютно то же самое, что и в Data Vault, и в якоре: таблицы «многие-ко-многим», которые содержат суррогатные ключи всех входящих сущностей, поля историзма, если они нужны, и поля партии сущностей, если связь гипербольшая.

Итого мы получаем примерно такую картинку: На логическом уровне рисуем ER-диаграмму или описываем нашу сущность.

g0lzdvb5tp3thva8zvwdjh22iam.jpeg

А на физическом уровне получаем вот такой набор таблиц. Видно, что тут есть и группы атрибутов, и просто атрибуты, и связи. Хотелось бы, чтобы все это было скрыто. Причем на обоих уровнях работы с DDS: и на загрузке данных, и на построении витрин.

p-1uacr2zzwbsoxtbfx5hv6v1us.jpeg

Мы скрываем физическую реализацию загрузки. Загрузка данных должна обеспечить идемпотентность, то есть мы можем загружать одни и те же данные сколько угодно раз, не ломая наш детальный слой. Грузиться должны параллельно все таблицы, это крайне желательно.

Мы хотим скрыть сложности загрузки SCD2. Если приходят данные, то мы в этом месте требуем, чтобы в слое DDS обязательно помимо ключа была еще дата, актуальная с точки зрения бизнеса, по которой мы простраиваем SCD2 в детальном слое.

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

Всего тут есть три концептуальные идеи:

  • Закрепить разделение логического и физического проектирования в методологии, полностью закрыть физическое проектирование.
  • Сокрытие физического проектирования провести как при загрузке данных, так и при использовании модели, чтобы было удобно загружать и строить витрины.
  • И так как мы все сокрыли с физической точки зрения, то нужно еще выбирать оптимальный формат хранения для каждого конкретного случая: группировать и догруппировать атрибуты. Все это скрыто внутри.

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

Из якоря мы взяли к ебе сам якорь. То есть мы не храним бизнес-ключи в ключевой таблице, а смотрим на них как на еще одни атрибуты. Связи идут через отдельную таблицу, как в Data Vault или якоре, но мы запретили вешать на них атрибуты. В перспективе хотим разрешить.

armnda6j2urerlaexj3ztje9bky.jpeg

Но с точки зрения простоты внедрения проще не думать, вешать ли атрибут на связь, а сразу знать: если на связь потребуется выделить атрибуты — создай новую сущность. Или подумай, что за сущность с этими атрибутами должна существовать.

Из Data Vault мы взяли специальные таблицы point in time и bridge для упрощения своей собственной внутренней работы с hNhM.

И если подводить итог, этим всем категорически невозможно управлять без фреймворка. Если вы попробуете все это воссоздать полуавтоматически или DDL-скриптами, то можно буквально убиться об количество таблиц и весь объем данных, метаданных, которыми надо управлять.

z2d008a7cff2ykjji_ru8p-zpnw.jpeg

Поэтому мы разработали так называемый hNhM-фреймворк. Здесь я передаю слово Коле. Он подробно расскажет, что мы конкретно разработали и как мы этим пользуемся у себя внутри.

— Да, я расскажу о нашем фреймворке — что сделали, как храним и как с этим работаем.

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

Смотреть доклад Владимира

В левой части — сервис репликации, написанный в Go на базе MongoDB, которая позволяет получать данные из всех возможных источников. Это может быть как реляционная база данных, так и нереляционная. Это может быть API, при этом и мы можем читать из API, и API может к нам пушить данные. То есть перед нами вещь, которая в себе собирает изменения.

ybzm1hsva4ydszciw9cy8-lz2ve.jpeg

В центральной части находится наш Data Lake, который хранится на YT. Это аналог экосистемы Hadoop, в нем мы храним слои RAW и ODS. Сейчас у нас объем данных — около двух петабайт.

И само хранилище на Greenplum, в котором находится частично ODS за очень небольшое количество времени и слой DDS. Сейчас Greenplum у нас весит, по-моему, около пол-петабайта. На каждом слое мы умеем вычислять инкремент, что позволяет ускорить загрузку, избавиться от лишней работы по чтению и обработке данных.

Детальный слой — основной элемент хранилища на Greenplum. На его основе мы строим все наши витрины.

hidq1jellco4kuktis1hzloysnk.jpeg

Отличительная особенность платформы: все сущности на всех слоях описываются в питонячем коде, но это видно и на слайде. Особенности описания сущностей в DDS мы рассмотрим на основе сущностей Person — «сотрудник».

3r2wqz6wfwiy9bd342zoj9nne3k.jpeg

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

Для чего нам нужна документация? На ее основе во время релиза платформа собирает документацию по всем нашим объектам и автоматически выкладывает на внутренний ресурс, это удобно для пользователей. Потому что им не надо следить за анонсами по изменению структуры. Они могут пойти в документацию, попробовать найти то, что им нужно, и начать пользоваться данными.

bwpbu_hnjsqopkmbbivn5yofbb0.jpeg

Далее необходимо описать техниче

© Habrahabr.ru