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

Пользовательские функции (User-defined functions)

Пользовательские функции (UDF) позволяют определять и регистрировать собственные функции непосредственно в вашем хранилище данных. Подобно макросам, UDF способствуют повторному использованию кода, но в отличие от макросов они являются объектами в хранилище. Это означает, что одну и ту же логику можно использовать не только в dbt, но и в других инструментах — например, в BI-системах, ноутбуках для data science и т.д.

UDF особенно полезны для переиспользования логики в нескольких инструментах, стандартизации сложных бизнес‑расчётов, повышения производительности вычислительно тяжёлых операций (поскольку они компилируются и оптимизируются движком запросов вашего хранилища), а также для контроля версий кастомной логики внутри вашего dbt‑проекта.

dbt создаёт, обновляет и переименовывает UDF в процессе выполнения DAG. UDF создаётся в хранилище до той модели, которая на него ссылается. Подробнее о том, как dbt строит UDF в проекте, см. listing and building UDFs.

Дополнительную информацию о конфигурациях и свойствах UDF см. в разделах Function properties и Function configurations.

Предварительные требования

  • Убедитесь, что вы используете Latest Fusion или Latest release track платформы dbt либо dbt Core версии v1.11.

  • Используйте один из следующих адаптеров:

    • BigQuery
    • Snowflake
    • Redshift
    • Postgres
    • Databricks
UDF support

При разработке UDF важно учитывать следующие ограничения поддержки:

  • Python UDF пока не поддерживаются в Fusion.
  • Дополнительные языки (например, Java, JavaScript, Scala) в настоящий момент не поддерживаются.

Полный список поддерживаемых возможностей UDF см. в разделе Limitations ниже.

Определение UDF в dbt

В dbt можно определять UDF на SQL и Python. Python UDF в настоящее время поддерживаются в Snowflake и BigQuery при использовании dbt Core.

Выполните следующие шаги, чтобы определить UDF в dbt:

  1. Создайте SQL‑ или Python‑файл в каталоге functions. Например, следующая UDF проверяет, представляет ли строка положительное целое число:

    Определение SQL UDF в SQL‑файле.

    functions/is_positive_int.sql
    # syntax for BigQuery, Snowflake, and Databricks
    REGEXP_INSTR(a_string, '^[0-9]+$')

    # syntax for Redshift and Postgres
    SELECT REGEXP_INSTR(a_string, '^[0-9]+$')

    Примечание: конфигурации можно указать либо в config‑блоке SQL‑файла, либо в соответствующем YAML‑файле со свойствами на следующем шаге (шаг 2).

  2. Укажите имя функции и задайте конфигурации, свойства, тип возвращаемого значения и (опционально) аргументы в соответствующем YAML‑файле со свойствами. Например:

    functions/schema.yml
    functions:
    - name: is_positive_int # required
    description: My UDF that returns 1 if a string represents a naked positive integer (like "10", "+8" is not allowed). # optional
    config:
    schema: udf_schema
    database: udf_db
    volatility: deterministic
    arguments: # optional
    - name: a_string # required if arguments is specified
    data_type: string # required if arguments is specified
    description: The string that I want to check if it's representing a positive integer (like "10")
    default_value: "'1'" # optional, available in Snowflake and Postgres
    returns: # required
    data_type: integer # required
    volatility зависит от хранилища данных

    Обратите внимание, что параметр volatility принимается dbt как для SQL‑, так и для Python‑UDF, но его обработка зависит от хранилища. BigQuery игнорирует volatility, и dbt выводит предупреждение. В Snowflake volatility применяется при создании UDF. Подробнее см. в разделе volatility.

  3. Выполните одну из следующих команд dbt build, чтобы собрать UDF и создать их в хранилище:

    Сборка всех UDF:

    dbt build --select "resource_type:function"

    Или сборка конкретной UDF:

    dbt build --select is_positive_int

    При выполнении dbt build файл functions/schema.yml и соответствующий SQL‑ или Python‑файл (например, functions/is_positive_int.sql или functions/is_positive_int.py) совместно используются для генерации оператора CREATE FUNCTION.

    Сгенерированный оператор CREATE FUNCTION зависит от используемого адаптера. Например:

    CREATE OR REPLACE FUNCTION udf_db.udf_schema.is_positive_int(a_string STRING DEFAULT '1')
    RETURNS INTEGER
    LANGUAGE SQL
    IMMUTABLE
    AS $$
    REGEXP_INSTR(a_string, '^[0-9]+$')
    $$;
  4. Используйте UDF в модели с помощью макроса {{ function(...) }}. Например:

    models/my_model.sql
    select
    maybe_positive_int_column,
    {{ function('is_positive_int') }}(maybe_positive_int_column) as is_positive_int
    from {{ ref('a_model_i_like') }}
  5. Выполните dbt compile, чтобы увидеть, как UDF подставляется в скомпилированный SQL. В следующем примере {{ function('is_positive_int') }} заменяется на имя UDF udf_db.udf_schema.is_positive_int.

    models/my_model.sql
    select
    maybe_positive_int_column,
    udf_db.udf_schema.is_positive_int(maybe_positive_int_column) as is_positive
    from analytics.dbt_schema.a_model_i_like

    В DAG создаётся узел UDF на основе SQL/Python‑файла и YAML‑описания, и появляется зависимость is_positive_intmy_model.

    DAG для узла UDFDAG для узла UDF

После определения UDF, если вы обновите SQL‑ или Python‑файл с телом функции либо её конфигурации, изменения будут применены к UDF в хранилище при следующем запуске build.

Использование UDF в unit‑тестах

Вы можете использовать unit tests для проверки моделей, которые ссылаются на UDF. Перед запуском unit‑тестов убедитесь, что функция существует в хранилище. Чтобы гарантировать это для unit‑теста, выполните:

dbt build --select "+my_model_to_test" --empty

Следуя примеру из раздела Определение UDF в dbt, ниже приведён пример unit‑теста, который проверяет модель, вызывающую UDF:

tests/test_is_positive_int.yml
unit_tests:
- name: test_is_positive_int
description: "Проверьте, что моя логика is_positive_int учитывает крайние случаи"
model: my_model
given:
- input: ref('a_model_i_like')
rows:
- { maybe_positive_int_column: 10 }
- { maybe_positive_int_column: -4 }
- { maybe_positive_int_column: +8 }
- { maybe_positive_int_column: 1.0 }
expect:
rows:
- { maybe_positive_int_column: 10, is_positive: true }
- { maybe_positive_int_column: -4, is_positive: false }
- { maybe_positive_int_column: +8, is_positive: true }
- { maybe_positive_int_column: 1.0, is_positive: true }

Просмотр и сборка UDF

Используйте команду list, чтобы вывести список UDF в проекте:
dbt list --select "resource_type:function" или dbt list --resource-type function.

Используйте команду build, чтобы выбирать UDF при сборке проекта:
dbt build --select "resource_type:function".

Подробнее о выборе UDF см. в примерах в разделе Node selector methods.

Ограничения

  • Создание UDF на других языках (например, Java, JavaScript или Scala) пока не поддерживается.
  • Python UDF в настоящее время поддерживаются только в Snowflake и BigQuery. Другие хранилища пока не поддерживаются.
  • Поддержка Python UDF в Fusion пока недоступна. Актуальные обновления см. в Fusion Diaries.
  • В настоящий момент поддерживаются только функции типов scalar и aggregate. Подробнее см. в разделе Supported function types.
Когда следует использовать UDF вместо макроса?

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

0
Loading