dbt: снэпшоты и метрики
Владимир ТрифоновДомашка
Давайте посмотрим наше домашнее задание. Оно было простое. Файл с источниками:
Файлы с моделями:
И напоследок файл с тестовыми идентификаторами:
Снэпшоты
Снэпшоты — это специальный инструмент в dbt, который позволяют делать снимок данных на текущий момент времени и сохранять его. Это может быть полезно для работы с данными, которые меняются со временем. Например, у вас может быть таблица с заказами в которой последовательно меняются статусы заказов: новый, укомплектован, отгружен и т.д. И при этом нет таблицы, хранящей историю изменений. А на вопрос, когда можно будет сделать — команда разработки отвечает: “в следующем квартале. Может быть”. Но теперь вы можете это сделать за вечер.
Обычно такие таблицы бывают в реляционный базах данных типа Postgres или Mysql. В базы данных типа BigQuery или Clickhouse данные зачастую стримятся из таких таблиц уже в виде снэпшотов.
Мы с вами сегодня сделаем снэпшот на немного искусственном примере: сделаем таблицу со статусами наших демо-такси, а потом вручную обновим их и сделаем снэпшот. Приступим.
Для начала создадим нашу таблицу с текущими статусами такси:
Добавим определение нового источника:
Теперь давайте определим снэпшот. По сути это будет обычная модель в папке snaphots, но со специальными обертками:
В target_schema мы указали датасет, где будут хранитmся снэпошоты. Unique_key
— идентификатор поля, по которому мы определяем наши сущности. Это может быть номер заказа или номер такси, как в нашем примере. strategy
— то, как мы определяем изменение. В данном случае изменением мы считаем изменение поля updated_at
.
Запустим команду dbt snapshot:
В результате видим, что dbt создал таблицу MH_Snapshots.taxi_status_snapshot
с тремя записями:
Тут нас в первую очередь интересуют столбы dbt_valid_from
и dbt_valid_to
. Они указывают на то, когда запись перешла в состояние и когда это состояние закончилось. Т.к. Мы сейчас сделали первый снэпшот и таблица еще не менялась, то dbt_valid_to
равно null
. Если еще раз запустить dbt snapshot
, то таблица не изменится:
Давайте теперь изменим одну запись:
Запустим dbt snapshot
и посмотрим, что вышло:
Мы видим, что dbt изменил две строки в таблице:
Обновил первую строку, указав время, до которого значение строки было актуально. И добавил еще одну строку с новыми данными, установив там только dbt_valid_from
. В нашем примере мы используем только один столбец, но если бы их было несколько, то dbt копировал бы всю строку целиком, у которой изменилось время updated_at
.
После этого снэпшот можно использовать, как обычную модель, обращаясь через ref(‘taxi_statuses’)
. Снэпшоты лучше всего делать первыми моделями, использующими источник, чтобы сохранить изменения как можно большего количества данных. И уже после этого обрабатывать их в моделях для нужд конвеера.
Т.к. Данные в моделях обычно изменяются в течение дня, а конвееры обычно считаются раз в день, то имеет смысл запускать создание снэпшотов чаще, например раз в час. К счастью, для их создания есть отдельная команда dbt snapshot
, которую вы можете запускать по cron или в dbt-cloud.
Метрики
Метрики позволяют рассчитывать агрегированные данные по заданным периодам и, при необходимости, в различных срезах. Пробежимся по ним в двух словах. Давайте сделаем метрику, определяющую количество поездок какого-то такси. Подключать метрики можно только к моделям. Давайте сделаем файл metrics.yml
:
Тут мы задаем название метрики name, описание метрики в поле label
, модель, на основе которой мы строим метрику. Затем мы выбираем тип агрегации метрики. Все виды вы можете посмотреть в документации по dbt. В нашем случае мы считаем уникальные значения. Затем идет sql код, который подставляется в агрегацию. timestamp определяет столбец, содержащий время, по которому мы строим метрику. А time_grains
— то, по каким временным срезам мы будет строить метрику. Последним в нашем примере идет параметр dimensions
. В нем мы указываем срезы, по которым мы будем считать метрику. В данном случае используем идентификатор такси.
Для того, чтобы обращаться к метрикам нам нужно подключить пакет dbt-labs/metrics
. Для этого добавьте его в файл packages.yml
(если его нет, то создайте его):
И запустите команду dbt deps
:
Затем посчитайте модель dbt_metrics_default_calendar
:
Она создаст простой календарь со всеми днями с 2010-01-01 по 2029-12-31 включительно:
После этого вы можете создать запрос к метрике. Давайте создадим модель taxi_trips_count.sql
:
И рассчитаем ее:
И посмотрим, что получилось:
Мы видим количество поездок по дням. Давайте изменим код модели и посчитаем количество поездок по неделям в разрезе машин:
И результат:
С помощью метрик у вас появляется единый источник данных для какой-то метрики по заданным срезам и вам не нужно больше каждый раз писать один и тот же код для разных вариантов. Dbt сделает это за вас, исключая ошибки. Ради интереса вы можете посмотреть файл target/compiled/mh_project/models/chicago_taxi_trips/taxi_trips_count.sql
.
Также вы можете делать метрики, построенные на других метриках. Например вы можете посчитать метрику количества сессий и расходов, а затем — CPC. Для этого нужно указать в качестве типа метрики derived
, а в calculation
— формулу, использующую другие метрики. Подробнее об этом — в документации.
Домашнее задание
В качестве домашнего задания сделайте снэпшот для таблицы с рейтингами фильмов. В качестве даты снэпшота — возьмите дату его создания.
Для метрик возьмите в качестве источника данные о продаже ликеров из таблицы bigquery-public-data.iowa_liquor_sales.sales
и сделайте метрику, считающую продажи по дням, неделям и месяцам в разрезе городов и описаний товара item_description
. Исключите город DAVENPORT
из расчета метрики. Постройте таблицу с продажами товаров по месяцам.