Конфигурация Starburst и Trino#

Требования к кластеру#

У выбранного кластера должен быть подключенный каталог, в котором можно создавать, переименовывать, изменять и удалять такие объекты, как таблицы и представления. Любой пользователь, подключающийся к кластеру через dbt, должен иметь те же права для целевого каталога.

Свойства сеанса#

В кластере Starburst Enterprise, Starburst Galaxy или Trino можно задавать свойства сеанса, чтобы изменять текущую конфигурацию пользовательского сеанса.

Стандартный способ определить свойства сеанса — поле session_properties в profiles.yml. Так все подключения dbt по умолчанию используют эти настройки.

Если нужно временно изменить свойства сеанса для конкретной модели dbt или группы моделей, используйте dbt hook, чтобы задать свойства сеанса на уровне конкретной модели. Например:

{{
  config(
    pre_hook="set session query_max_run_time='10m'"
  )
}}

Свойства коннектора#

Свойства таблиц Starburst и Trino можно использовать для настройки того, как представляются данные.

Подробности о поддержке для конкретного источника данных см. в документации коннекторов Trino или каталогов Starburst.

Каталоги Hive#

При работе со Starburst и dbt часто используется целевой каталог на базе коннектора Hive и службы metastore (HMS). Для работы с dbt рекомендуются следующие настройки. Их цель — обеспечить возможность частого выполнения операторов DROP и RENAME, которые использует dbt.

hive.metastore-cache-ttl=0s
hive.metastore-refresh-interval=5s

Конфигурация формата файлов#

При использовании файловых коннекторов, например Hive, пользователь может настраивать отдельные аспекты коннектора, включая формат данных и тип materialization.

В следующем примере таблица материализуется как набор секционированных файлов Parquet.

{{
  config(
    materialized='table',
    properties= {
      "format": "'PARQUET'",
      "partitioning": "ARRAY['bucket(id, 2)']",
    }
  )
}}

Seeds и подготовленные операторы#

Команда dbt seed использует подготовленные операторы в Starburst и Trino.

Подготовленные операторы — это шаблонные SQL-операторы, которые можно эффективно выполнять повторно. Значения отправляются в отдельном поле, а не жестко прописываются в самой SQL-строке. Так часто устроены INSERT-операторы записей в OLTP-бэкендах приложений. Поэтому у подготовленных операторов часто столько placeholder-переменных, сколько столбцов в целевой таблице.

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

Ограничение длины строки заголовка в Python HTTP client#

Если в подготовленных операторах слишком много параметров, можно столкнуться с ошибкой о лимите строки заголовка. Причина в том, что лимит строки заголовка в Python HTTP client равен 65536 байтам.

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

Предположим, есть seed-файл с 20 столбцами, 600 строками и 12 000 параметрами. Вместо создания одного подготовленного оператора dbt может создать четыре подготовленных оператора INSERT по 150 строк и 3 000 параметров.

У группировки строк таблицы есть недостаток. Если в seed-файле много столбцов (параметров), размер пакета должен быть очень маленьким.

Для адаптера dbt-trino макрос размера пакета называется trino__get_batch_size(), а его значение по умолчанию — 1000. Чтобы изменить это поведение по умолчанию, добавьте такой макрос в dbt-проект.

Файл macros/YOUR_MACRO_NAME.sql:

{% macro trino__get_batch_size() %}
  {{ return(10000) }} -- Настройте это число под свои задачи
{% endmacro %}

Еще один способ избежать лимита длины строки заголовка — установить prepared_statements_enabled в true в профиле dbt. Однако это считается устаревшим поведением и может быть удалено в будущем релизе.

Materializations#

Table#

Адаптер dbt-trino поддерживает следующие режимы для materialization table (а также для запусков full-refresh в materialization incremental). Режим настраивается параметром on_table_exists:

  • rename — создает промежуточную таблицу, переименовывает целевую таблицу в резервную и переименовывает промежуточную таблицу в целевую.

  • drop — удаляет и заново создает таблицу. Это позволяет обойти ограничение переименования таблиц в AWS Glue.

  • replace — заменяет таблицу с помощью предложения CREATE OR REPLACE. Поддержка замены таблиц зависит от коннектора. Подробности см. в документации соответствующего коннектора.

  • skip — полностью пропускает materialization таблицы, используя предложение CREATE TABLE IF NOT EXISTS.

Если базовый коннектор поддерживает CREATE OR REPLACE, рекомендуется использовать replace. В противном случае рекомендуемая materialization table использует on_table_exists = 'rename'; это также значение по умолчанию. Настройку по умолчанию можно изменить в одном из файлов:

  • SQL-файл модели.

  • Конфигурационный файл dbt_project.yml.

Следующие примеры настраивают materialization table на режим drop.

Файл models/YOUR_MODEL_NAME.sql:

{{
  config(
    materialized = 'table',
    on_table_exists = 'drop'
  )
}}

Файл dbt_project.yml:

models:
  path:
    materialized: table
    +on_table_exists: drop

Если используется materialization table и on_table_exists = 'rename' с AWS Glue, может появиться следующая ошибка. Обойти ограничение переименования таблиц можно с помощью drop:

TrinoUserError(type=USER_ERROR, name=NOT_SUPPORTED, message="Table rename is not yet supported by Glue service")

View#

Адаптер dbt-trino поддерживает следующие режимы безопасности для materialization view, которые настраиваются через view_security:

  • definer

  • invoker

Подробнее о режимах безопасности в представлениях см. раздел Security в документации Trino.

По умолчанию materialization view использует view_security = 'definer'. Эту настройку по умолчанию можно изменить в одном из файлов:

  • SQL-файл модели.

  • Конфигурационный файл dbt_project.yml.

Например, следующие настройки задают режим безопасности invoker.

Файл models/YOUR_MODEL_NAME.sql:

{{
  config(
    materialized = 'view',
    view_security = 'invoker'
  )
}}

Файл dbt_project.yml:

models:
  path:
    materialized: view
    +view_security: invoker

Incremental#

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

{{
    config(
      materialized = 'incremental',
      unique_key='<optional>',
      incremental_strategy='<optional>',)
}}
select * from {{ ref('events') }}
{% if is_incremental() %}
  where event_ts > (select max(event_ts) from {{ this }})
{% endif %}

Используйте свойство +on_schema_change, чтобы определить, как dbt-trino должен обрабатывать изменения столбцов. Подробнее об этом свойстве см. в разделе column changes.

Если коннектор не поддерживает представления, установите свойство +views_enabled в false.

Можно определить, как модель должна пересоздаваться при запуске full-refresh, указав конфигурацию on_table_exists. Варианты совпадают с описанными выше в разделе materialization table.

Стратегия append#

Инкрементальная стратегия по умолчанию — append. append только добавляет новые записи на основе условия, указанного в условном блоке is_incremental().

{{
    config(
      materialized = 'incremental')
}}
select * from {{ ref('events') }}
{% if is_incremental() %}
  where event_ts > (select max(event_ts) from {{ this }})
{% endif %}

Стратегия delete+insert#

Стратегия delete+insert позволяет указать dbt использовать двухшаговый инкрементальный подход. Сначала dbt удаляет записи, найденные через настроенный блок is_incremental(), затем вставляет их заново.

{{
    config(
      materialized = 'incremental',
      unique_key='user_id',
      incremental_strategy='delete+insert',
      )
}}
select * from {{ ref('users') }}
{% if is_incremental() %}
  where updated_ts > (select max(updated_ts) from {{ this }})
{% endif %}

Стратегия merge#

При стратегии merge dbt-trino строит оператор MERGE Trino, чтобы вставлять новые записи и обновлять существующие на основе свойства unique_key.

Если unique_key не уникален, можно использовать стратегию delete+insert.

{{
    config(
      materialized = 'incremental',
      unique_key='user_id',
      incremental_strategy='merge',
      )
}}
select * from {{ ref('users') }}
{% if is_incremental() %}
  where updated_ts > (select max(updated_ts) from {{ this }})
{% endif %}

Учитывайте, что некоторые коннекторы Trino не поддерживают MERGE или поддерживают его ограниченно.

Инкрементальная перезапись в моделях Hive#

Если целевая инкрементальная модель доступна через коннектор Hive, можно сымитировать оператор INSERT OVERWRITE с помощью настройки insert-existing-partitions-behavior в конфигурации коннектора Hive в Trino:

<hive-catalog-name>.insert-existing-partitions-behavior=OVERWRITE

Ниже пример конфигурации Hive, которая задает функциональность OVERWRITE для коннектора Hive с именем minio:

trino-incremental-hive:
  target: dev
  outputs:
    dev:
      type: trino
      method: none
      user: admin
      password:
      catalog: minio
      schema: tiny
      host: localhost
      port: 8080
      http_scheme: http
      session_properties:
        minio.insert_existing_partitions_behavior: OVERWRITE
      threads: 1

dbt-trino перезаписывает существующие секции в целевой модели, которые соответствуют staged-данным. Остальные секции добавляются к целевой модели. Эта возможность работает для инкрементальных моделей, использующих секционирование. Например:

{{
    config(
        materialized = 'incremental',
        properties={
          "format": "'PARQUET'",
          "partitioned_by": "ARRAY['day']",
        }
    )
}}

Materialized view#

Адаптер dbt-trino поддерживает материализованные представления и обновляет их при каждом последующем выполнении dbt run. Подробнее см. REFRESH MATERIALIZED VIEW в документации Trino.

Пользовательские свойства материализованного представления можно задать через конфигурацию properties.

Эта materialization поддерживает конфигурацию и флаг full_refresh. Если нужно пересобрать материализованное представление, например при изменении базового SQL-запроса, выполните dbt run --full-refresh.

Материализованное представление можно создать, изменив один из файлов:

  • SQL-файл модели.

  • Конфигурационный файл dbt_project.yml.

Следующие примеры создают материализованное представление в формате Parquet.

Файл models/YOUR_MODEL_NAME.sql:

{{
  config(
    materialized = 'materialized_view',
    properties = {
      'format': "'PARQUET'"
    },
  )
}}

Файл dbt_project.yml:

models:
  path:
    materialized: materialized_view
    properties:
      format: "'PARQUET'"

Snapshots#

Snapshots в dbt зависят от макроса current_timestamp, который по умолчанию возвращает timestamp с миллисекундной точностью (3 знака). Некоторые коннекторы Trino, например Iceberg, не поддерживают такую точность timestamp (TIMESTAMP(3) WITH TIME ZONE).

Чтобы изменить точность timestamp, можно определить собственный макрос. Например, следующий макрос задает новый trino__current_timestamp() с микросекундной точностью (6 знаков).

Файл macros/YOUR_MACRO_NAME.sql:

{% macro trino__current_timestamp() %}
    current_timestamp(6)
{% endmacro %}

Grants#

Используйте grants для управления доступом к наборам данных, которые вы создаете с помощью dbt. Grants можно использовать со Starburst Enterprise, Starburst Galaxy и Hive (sql-standard).

Чтобы реализовать права доступа, определите grants как resource configs для каждой модели, seed и snapshot. Grants по умолчанию для всего проекта задаются в dbt_project.yml, а grants для конкретной модели — в SQL- или YAML-файле этой модели.

Файл dbt_project.yml:

models:
  - name: NAME_OF_YOUR_MODEL
    config:
      grants:
        select: ['reporter', 'bi']

Контракты моделей#

Адаптер dbt-trino поддерживает контракты моделей. В настоящее время поддерживаются только constraints с type равным not_null.

Перед использованием ограничений not_null в модели убедитесь, что базовый коннектор поддерживает not null, чтобы избежать ошибок.