Мартс: Определяемые бизнесом сущности
Наши рекомендации здесь различаются в зависимости от того, используете ли вы Семантический слой dbt. В проекте без Семантического слоя мы рекомендуем сильно денормализовать данные, следуя приведенным ниже лучшим практикам. С другой стороны, если вы используете Семантический слой, мы стремимся оставаться максимально нормализованными, чтобы предоставить MetricFlow максимальную гибкость. Рекомендации по мартсам в контексте Семантического слоя находятся на следующей странице.
Это слой, где все объединяется, и мы начинаем организовывать все наши атомы (модели подготовки) и молекулы (промежуточные модели) в полноценные клетки, которые имеют идентичность и цель. Мы иногда называем это слоем сущностей или слоем концепций, чтобы подчеркнуть, что все наши мартсы предназначены для представления конкретной сущности или концепции на ее уникальном уровне детализации. Например, заказ, клиент, территория, событие клика, платеж — каждая из этих сущностей будет представлена отдельным мартсом, и каждая строка будет представлять отдельный экземпляр этих концепций. В отличие от традиционной звездообразной схемы Кимбалла, в современном хранении данных — где хранение дешево, а вычисления дороги — мы с удовольствием заимствуем и добавляем любые данные из других концепций, которые имеют отношение к ответам на вопросы о основной сущности мартса. Создание одних и тех же данных в нескольких местах, как мы делаем с orders
в нашем примере мартса customers
ниже, более эффективно в этой парадигме, чем повторное соединение этих концепций (это базовое определение денормализации в этом контексте). Давайте посмотрим, как мы подходим к этому первому слою, предназначенному специально для предоставления конечным пользователям.
Мартсы: Файлы и папки
Последний слой наших основных преобразований представлен ниже, предоставляя модели для отделов finance
и marketing
.
models/marts
├── finance
│ ├── _finance__models.yml
│ ├── orders.sql
│ └── payments.sql
└── marketing
├── _marketing__models.yml
└── customers.sql
✅ Группировка по отделу или области интересов. Если у вас меньше 10 или около того мартсов, вам может не понадобиться много подпапок, поэтому, как и с промежуточным слоем, не переоптимизируйте слишком рано. Если вы все же обнаружите, что вам нужно добавить больше структуры и группировки, используйте здесь полезные бизнес-концепции. В нашем слое мартсов мы больше не беспокоимся о данных, согласованных с источником, поэтому группировка по отделам (маркетинг, финансы и т.д.) является наиболее распространенной структурой на этом этапе.
✅ Назовите по сущности. Используйте простой английский язык для названия файла на основе концепции, которая формирует зерно мартса, например customers
, orders
. Мартсы, которые не включают временные свертки (чистые мартсы), не должны иметь временного измерения (orders_per_day
) здесь, обычно лучше всего фиксируемого через метрики.
❌ Создавайте одну и ту же концепцию по-разному для разных команд. finance_orders
и marketing_orders
обычно считаются антипаттерном. Как всегда, есть исключения — распространенный шаблон, который мы видим, заключается в том, что финансы могут иметь специфические потребности, например, отчетность о доходах для правительства, которая отличается от того, как компания в целом измеряет доходы ежедневно. Просто убедитесь, что они четко спроектированы и понятны как отдельные концепции, а не как ведомственные представления одной и той же концепции: tax_revenue
и revenue
, а не finance_revenue
и marketing_revenue
.
Мартсы: Модели
Наконец, мы рассмотрим лучшие практики для моделей в каталоге мартсов, изучив две из наших моделей мартсов. Это бизнес-согласованные — то есть созданные в соответствии с нашим видением и потребностями — сущности, которые мы объединяем из этих преобразованных компонентов.
-- orders.sql
with
orders as (
select * from {{ ref('stg_jaffle_shop__orders' )}}
),
order_payments as (
select * from {{ ref('int_payments_pivoted_to_orders') }}
),
orders_and_order_payments_joined as (
select
orders.order_id,
orders.customer_id,
orders.order_date,
coalesce(order_payments.total_amount, 0) as amount,
coalesce(order_payments.gift_card_amount, 0) as gift_card_amount
from orders
left join order_payments on orders.order_id = order_payments.order_id
)
select * from orders_and_payments_joined
-- customers.sql
with
customers as (
select * from {{ ref('stg_jaffle_shop__customers')}}
),
orders as (
select * from {{ ref('orders')}}
),
customer_orders as (
select
customer_id,
min(order_date) as first_order_date,
max(order_date) as most_recent_order_date,
count(order_id) as number_of_orders,
sum(amount) as lifetime_value
from orders
group by 1
),
customers_and_customer_orders_joined as (
select
customers.customer_id,
customers.first_name,
customers.last_name,
customer_orders.first_order_date,
customer_orders.most_recent_order_date,
coalesce(customer_orders.number_of_orders, 0) as number_of_orders,
customer_orders.lifetime_value
from customers
left join customer_orders on customers.customer_id = customer_orders.customer_id
)
select * from customers_and_customer_orders_joined
- ✅ Материализованы как таблицы или инкрементальные модели. Как только мы достигаем слоя мартсов, пора начинать строить не только нашу логику в хранилище, но и сами данные. Это дает конечным пользователям г ораздо более высокую производительность для этих поздних моделей, которые действительно предназначены для их использования, и экономит нам затраты на пересчет этих целых цепочек моделей каждый раз, когда кто-то обновляет дашборд или запускает регрессию в Python. Хорошее общее правило относительно материализации — всегда начинать с представления (так как оно практически не занимает места и всегда дает актуальные результаты), как только это представление занимает слишком много времени для практического запроса, создайте его в таблице, и, наконец, как только эта таблица занимает слишком много времени для создания и замедляет ваши запуски, настройте ее как инкрементальную модель. Как всегда, начните с простого и добавляйте сложность только по мере необходимости. Модели с наибольшим объемом данных и вычислительно интенсивными преобразованиями должны обязательно использовать отличные возможности dbt для инкрементальной материализации, но спешка сделать все ваши модели мартсов инкрементальными по умолчанию введет излишнюю сложност ь. Мы рекомендуем прочитать этот классический пост от Тристана о пределах инкрементального моделирования.
- ✅ Широкие и денормализованные. В отличие от старой школы хранения данных, в современном стеке данных хранение дешево, и именно вычисления дороги и должны быть приоритетными, упаковывая их в очень широкие денормализованные концепции, которые могут предоставить все, что кому-то нужно о концепции, как цель.
- ❌ Слишком много соединений в одном мартсе. Одно хорошее правило при построении преобразований dbt — избегать объединения слишком многих концепций в одном мартсе. Что составляет 'слишком много', может варьироваться. Если вам нужно объединить 8 моделей подготовки с помощью простых соединений, это может быть нормально. Напротив, если у вас есть 4 концепции, которые вы объединяете с помощью сложных и вычислительно тяжелых оконных функций, это может быть слишком много. Вам нужно взвесить количество моделей, которые вы объединяете, против сложности логики внутри мартса, и если это слишком много, чтобы прочитать и построить четкую ментальную модель, то стоит модульно разделить. Хотя это не жесткое правило, если вы объединяете более 4 или 5 концепций для создания вашего мартса, вы можете извлечь выгоду из добавления некоторых промежуточных моделей для большей ясности. Две промежуточные модели, которые объединяют три концепции каждая, и мартс, который объединяет эти две промежуточные модели, обычно приведут к гораздо более читаемой цепочке логики, чем один мартс с шестью соединениями.
- ✅ Создавайте на отдельных мартсах обдуманно. Хотя мы стремимся сохранить сужающуюся DAG до слоя мартсов, здесь вещи могут начать становиться немного менее строгими. Распространенный пример — передача информации между мартсами на разных уровнях детализации, как мы видели выше, где мы переносим наш мартс
orders
в наш мартсcustomers
, чтобы агрегировать критические данные о заказах в зерноcustomer
. Теперь, когда мы действительно 'тратим' вычисления и хранение, фактически создавая данные в наших выходных данных, разумно использовать ранее созданные ресурсы, чтобы ускорить и сэкономить на выходных данных, требующих аналогичных данных, вместо пересчета тех же представлений и CTE с нуля. Правильный подход здесь сильно зависит от вашей уникальной DAG, моделей и целей — важно просто отметить, что использование мартса при создании другого, более позднего мартса допустимо, но требует тщательного рассмотрения, чтобы избежать потери ресурсов или циклических зависимостей.
Наиболее важный аспект мартсов заключается в том, что они содержат все полезные данные о конкретной сущности на детальном уровне. Это не значит, что мы не привлекаем множество других сущностей и концепций, таких как множество данных user
в наш мартс orders
, мы это делаем! Это просто означает, что отдельные orders
остаются основным зерном нашей таблицы. Если мы начинаем группировать users
и orders
вдоль временной оси, в нечто вроде user_orders_per_day
, мы выходим за рамки мартсов в метрики.
Мартсы: Другие соображения
- Устранение неполадок через таблицы. Хотя наложение представлений и эфемерных моделей до наших мартсов — построение данных в хранилище только в конце цепочки, когда у нас есть модели, с которыми мы действительно хотим, чтобы конечные пользователи работали — идеально в производстве, это может представлять некоторые трудности в разработке. В частности, определенные ошибки могут казаться возникающими в наших более поздних моделях, которые на самом деле происходят из гораздо более ранних зависимостей в нашей цепочке моделей (предшествующих моделей в нашей DAG, которые строятся до того, как модель выдает ошибки). Если у вас возникают трудности с определением, где или что говорит вам ошибка базы данных, может быть полезно временно построить конкретную цепочку моделей как таблицы, чтобы хранилище выдало ошибку там, где она действительно происходит.
Семантический слой dbt и мартсы
Наши структурные рекомендации значительно зависят от того, используете ли вы Семантический слой dbt. Если вы используете Семантический слой, мы рекомендуем более нормализованный подход к вашим мартсам. Если вы не используете Семантический слой, мы рекомендуем более денормализованный подход, который стал типичным в проектах dbt. Для полного списка рекомендаций по структуре, наименованию и организации в Семантическом слое, ознакомьтесь с руководством Как мы строим наши метрики, особенно с разделом Рефакторинг существующей свертки.