Перейти к основному содержимому

Добавление снапшотов в ваш DAG

Учитесь с помощью видео!
Чтобы посмотреть видеоуроки по теме Snapshots, перейдите в dbt Learn и ознакомьтесь с курсом Snapshots.

Что такое снимки?

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

Снимки реализуют тип-2 медленно изменяющихся измерений в изменяемых исходных таблицах. Эти медленно изменяющиеся измерения (или SCD) определяют, как строка в таблице изменяется с течением времени. Представьте, что у вас есть таблица orders, где поле status может быть перезаписано по мере обработки заказа.

idstatusupdated_at
1pending2024-01-01
Loading table...

Теперь представьте, что заказ переходит из состояния "pending" в "shipped". Эта же запись теперь будет выглядеть так:

idstatusupdated_at
1shipped2024-01-02
Loading table...

Этот заказ теперь в состоянии "shipped", но мы потеряли информацию о том, когда заказ в последний раз находился в состоянии "pending". Это затрудняет (или делает невозможным) анализ того, сколько времени потребовалось для отправки заказа. dbt может "сделать снимок" этих изменений, чтобы помочь вам понять, как значения в строке изменяются с течением времени. Вот пример таблицы снимков для предыдущего примера:

idstatusupdated_atdbt_valid_fromdbt_valid_to
1pending2024-01-012024-01-012024-01-02
1shipped2024-01-022024-01-02null
Loading table...

Конфигурирование снимков

Лучшие практики конфигурации

 Используйте стратегию timestamp, где это возможно

Стратегия timestamp рекомендуется, потому что она более эффективно обрабатывает добавление и удаление колонок по сравнению со стратегией check. Это связано с тем, что она более устойчива к изменениям схемы, особенно когда со временем в таблице появляются новые колонки или удаляются существующие.

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

Почему timestamp — предпочтительная стратегия:

  • Требуется отслеживать только одну колонку (updated_at)
  • Автоматически обрабатывает появление новых или удаление существующих колонок в исходной таблице
  • Меньше подвержена ошибкам при изменении схемы таблицы со временем (например, при использовании стратегии check может потребоваться обновлять параметр check_cols)
 Используйте dbt_valid_to_current для упрощения запросов по диапазону дат

По умолчанию dbt_valid_to равно NULL для текущих записей. Однако, если вы установите конфигурацию dbt_valid_to_current (доступно в dbt Core v1.9+), dbt_valid_to будет установлено в указанное вами значение (например, 9999-12-31) для текущих записей.

Это позволяет легко фильтровать по диапазону дат.

 Убедитесь, что ваш уникальный ключ действительно уникален

Уникальный ключ используется dbt для сопоставления строк, поэтому крайне важно убедиться, что этот ключ действительно уникален! Если вы делаете снимок источника, я рекомендую добавить тест на уникальность в ваш источник (пример).

Как работают снимки

Когда вы запускаете команду dbt snapshot:

  • При первом запуске: dbt создаст исходную таблицу снапшота — это будет результат выполнения вашего select‑запроса с добавленными колонками, включая dbt_valid_from и dbt_valid_to. Для всех записей значение dbt_valid_to будет равно null либо значению, заданному в dbt_valid_to_current (доступно начиная с dbt Core 1.9+), если эта настройка сконфигурирована.
  • При последующих запусках: dbt проверит, какие записи изменились, а также появились ли новые записи:
    • Колонка dbt_valid_to будет обновлена для всех существующих записей, которые изменились.
    • Обновлённые записи и все новые записи будут вставлены в таблицу снапшота. Для этих записей значение dbt_valid_to будет равно null либо значению, заданному в dbt_valid_to_current (доступно в dbt Core v1.9+).

Снимки могут быть использованы в последующих моделях так же, как и модели — с помощью функции ref.

Обнаружение изменений строк

Стратегии снимков определяют, как dbt узнает, изменилась ли строка. В dbt встроены две стратегии:

  • Timestamp — Использует колонку updated_at, чтобы определить, изменилась ли строка.
  • Check — Сравнивает список колонок между их текущими и историческими значениями, чтобы определить, изменилась ли строка.

Стратегия timestamp использует поле updated_at, чтобы определить, изменилась ли строка. Если настроенная колонка updated_at для строки более новая, чем в последний раз, когда снимок запускался, то dbt аннулирует старую запись и запишет новую. Если временные метки не изменились, то dbt не предпримет никаких действий.

Почему рекомендуется использовать timestamp?

  • Требуется отслеживать только одну колонку (updated_at)
  • Автоматически обрабатывает появление новых или удаление существующих колонок в исходной таблице
  • Меньше подвержен ошибкам при эволюции схемы таблицы со временем (например, при использовании стратегии check может потребоваться обновлять конфигурацию check_cols)

Стратегия timestamp требует следующих настроек:

КонфигурацияОписаниеПример
updated_atСтолбец, который отражает момент последнего обновления строки источника. В зависимости от используемой платформы данных может поддерживать строки дат в формате ISO и целые числа unix epoch.updated_at
Loading table...

Пример использования:

Стратегия Check

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

Стратегия check требует следующих конфигураций:

КонфигурацияОписаниеПример
check_colsСписок колонок для проверки изменений или all для проверки всех колонок["name", "email"]
Loading table...
check_cols = 'all'

Стратегия снимков check может быть настроена для отслеживания изменений всех колонок, указав check_cols = 'all'. Лучше явно перечислить колонки, которые вы хотите проверить. Рассмотрите возможность использования surrogate key для конденсации многих колонок в одну.

Пример использования

Пример использования с updated_at

При использовании стратегии check dbt отслеживает изменения, сравнивая значения в check_cols. По умолчанию dbt использует текущее время выполнения, чтобы заполнять поля dbt_updated_at, dbt_valid_from и dbt_valid_to. При этом вы можете дополнительно указать колонку updated_at:

  • Если updated_at настроена, стратегия check будет использовать эту колонку вместо времени выполнения, аналогично стратегии timestamp.
  • Если значение updated_at равно null, dbt по умолчанию использует текущее время.

Рассмотрим следующий пример, который показывает, как использовать стратегию check с updated_at:

snapshots:
- name: orders_snapshot
relation: ref('stg_orders')
config:
schema: snapshots
unique_key: order_id
strategy: check
check_cols:
- status
- is_cancelled
updated_at: updated_at

В этом примере:

  • Если изменяется хотя бы одно из указанных значений в check_cols, снапшот создаёт новую строку. Если колонка updated_at содержит значение (не равна null), снапшот использует его; в противном случае используется текущее время.
  • Если updated_at не задана, dbt автоматически возвращается к использованию текущего времени для отслеживания изменений.
  • Используйте этот подход, если ваша колонка updated_at не всегда надёжна для отслеживания обновлений записей, но вы всё равно хотите применять её — вместо времени выполнения снапшота — когда изменения строк всё же обнаружены.

Жёсткие удаления (opt-in)

Метаполя snapshot

Снимки таблицы будут созданы как клон вашего исходного набора данных, плюс некоторые дополнительные мета-поля*.

В dbt Core версии 1.9+ (или доступно раньше в треке релизов «Latest» для dbt):

  • Эти имена колонок можно настроить в соответствии с командными или организационными соглашениями с помощью конфига snapshot_meta_column_names.
  • Используйте конфиг dbt_valid_to_current, чтобы задать пользовательский индикатор значения dbt_valid_to для текущих записей снапшота (например, будущую дату вроде 9999-12-31). По умолчанию это значение равно NULL. Если оно задано, dbt будет использовать указанное значение вместо NULL для dbt_valid_to у текущих записей в таблице снапшота.
  • Используйте конфиг hard_deletes для отслеживания удалённых записей как новых строк с мета-полем dbt_is_deleted при использовании значения hard_deletes='new_record'.
Field
Значение
ПримечанияПример
dbt_valid_fromВременная метка, когда эта строка снапшота была впервые вставлена и стала валидной.Эту колонку можно использовать для упорядочивания различных «версий» записи.snapshot_meta_column_names: {dbt_valid_from: start_date}
dbt_valid_toВременная метка, когда эта строка стала невалидной. Для текущих записей по умолчанию это NULL или значение, указанное в dbt_valid_to_current.Самая последняя запись снапшота будет иметь dbt_valid_to, равное NULL или указанному значению.snapshot_meta_column_names: {dbt_valid_to: end_date}
dbt_scd_idУникальный ключ, сгенерированный для каждой строки снапшота.Используется внутри dbt.snapshot_meta_column_names: {dbt_scd_id: scd_id}
dbt_updated_atВременная метка updated_at исходной записи на момент вставки этой строки снапшота.Используется внутри dbt.snapshot_meta_column_names: {dbt_updated_at: modified_date}
dbt_is_deletedСтроковое значение, указывающее, была ли запись удалена (True — удалена, False — не удалена).Добавляется, когда сконфигурирован hard_deletes='new_record'.snapshot_meta_column_names: {dbt_is_deleted: is_deleted}
Loading table...

Все эти имена колонок можно настроить с помощью конфига snapshot_meta_column_names. Подробнее см. в этом примере.

*Временные метки, используемые для каждой колонки, немного различаются в зависимости от используемой стратегии:

  • Для стратегии timestamp настроенная колонка updated_at используется для заполнения колонок dbt_valid_from, dbt_valid_to и dbt_updated_at.

     Sample results for the timestamp strategy

    Результаты snapshot‑запроса на момент 2024-01-01 11:00

    idstatusupdated_at
    1pending2024-01-01 10:47
    Loading table...

    Результаты снапшота (обратите внимание, что 11:00 нигде не используется):

    idstatusupdated_atdbt_valid_fromdbt_valid_todbt_updated_at
    1pending2024-01-01 10:472024-01-01 10:472024-01-01 10:47
    Loading table...

    Результаты запроса на момент 2024-01-01 11:30:

    idstatusupdated_at
    1shipped2024-01-01 11:05
    Loading table...

    Результаты snapshot (обратите внимание, что 11:30 нигде не используется):

    idstatusupdated_atdbt_valid_fromdbt_valid_todbt_updated_at
    1pending2024-01-01 10:472024-01-01 10:472024-01-01 11:052024-01-01 10:47
    1shipped2024-01-01 11:052024-01-01 11:052024-01-01 11:05
    Loading table...

    Результаты snapshot при hard_deletes='new_record':

    idstatusupdated_atdbt_valid_fromdbt_valid_todbt_updated_atdbt_is_deleted
    1pending2024-01-01 10:472024-01-01 10:472024-01-01 11:052024-01-01 10:47False
    1shipped2024-01-01 11:052024-01-01 11:052024-01-01 11:202024-01-01 11:05False
    1deleted2024-01-01 11:202024-01-01 11:202024-01-01 11:20True
    Loading table...
  • Для стратегии check текущая временная метка используется для заполнения каждого столбца. Если настроено, стратегия check вместо этого использует столбец updated_at, как и стратегия временных меток.

 Пример результатов для стратегии check

Результаты snapshot-запроса на момент 2024-01-01 11:00

idstatus
1pending
Loading table...

Snapshot results:

idstatusdbt_valid_fromdbt_valid_todbt_updated_at
1pending2024-01-01 11:002024-01-01 11:00
Loading table...

Query results at 2024-01-01 11:30:

idstatus
1shipped
Loading table...

Snapshot results:

idstatusdbt_valid_fromdbt_valid_todbt_updated_at
1pending2024-01-01 11:002024-01-01 11:302024-01-01 11:00
1shipped2024-01-01 11:302024-01-01 11:30
Loading table...

Snapshot results with hard_deletes='new_record':

idstatusdbt_valid_fromdbt_valid_todbt_updated_atdbt_is_deleted
1pending2024-01-01 11:002024-01-01 11:302024-01-01 11:00False
1shipped2024-01-01 11:302024-01-01 11:402024-01-01 11:30False
1deleted2024-01-01 11:402024-01-01 11:40True
Loading table...

Часто задаваемые вопросы

Как запустить один снимок за раз?
Как часто следует запускать команду snapshot?
Что произойдет, если я добавлю новые столбцы в запрос снимка?
Выполняются ли хуки со снапшотами?
Могу ли я хранить snapshot’ы в директории, отличной от директории `snapshot` в моем проекте?
Ошибка: Целевая таблица снимка не является таблицей снимков

Нашли ошибку?

0
Loading