Пользовательские функции SQL и Python (UDF) в Unity Catalog

Внимание

Эта функция доступна в общедоступной предварительной версии.

Определяемые пользователем функции в каталоге Unity расширяют возможности SQL и Python в Azure Databricks. Они позволяют определять, использовать и безопасно предоставлять общий доступ и управлять пользовательскими функциями в вычислительных средах.

Зарегистрированные в Unity Catalog функции Python (UDFs) отличаются по области и поддержке от функций PySpark UDFs, привязанных к записной книжке или сеансу SparkSession. См. определяемые пользователем скалярные функции Python (UDF).

Чтобы зарегистрировать пользовательские функции (UDF), написанные на Scala или Java, в Unity Catalog, см. статью Пользовательские функции (UDF) на Scala и Java в Unity Catalog.

Полное справочное руководство по языку SQL см. в разделе CREATE FUNCTION (SQL, Python, Scala и Java).

Требования

Чтобы использовать ППФ в каталоге Unity, необходимо удовлетворять следующим требованиям:

  • Чтобы использовать код Python в определяемых пользователем функциях (UDF), зарегистрированных в Unity Catalog, необходимо использовать бессерверное или профессиональное хранилище SQL или кластер под управлением Databricks Runtime 13.3 LTS или более поздней версии.
  • Если представление содержит Python UDF из Unity Catalog, оно завершается сбоем в классических хранилищах SQL.
  • Поддержка экземпляра ARM для кластеров с поддержкой каталога Unity Scala доступна в Databricks Runtime 15.2 и более поздних версиях.

Создание пользовательских функций SQL и Python в Unity Catalog

Чтобы создать UDF SQL или Python в Unity Catalog, пользователям необходимы разрешения USAGE и CREATE для схемы, а также разрешение USAGE для каталога. Дополнительные сведения см. в каталоге Unity .

Чтобы запустить UDF, требуется, чтобы пользователи имели разрешение EXECUTE на UDF. Пользователям также требуется разрешение USAGE на схему и каталог.

Чтобы создать и зарегистрировать UDF в схеме каталога Unity, имя функции должно соответствовать формату catalog.schema.function_name. Кроме того, можно выбрать правильный каталог и схему в редакторе SQL. В этом случае перед именем функции не должно быть catalog.schema:

Создание UDF с предварительно выбранным каталогом и схемой.

В следующем примере регистрируется новая функция в my_schema схеме в каталоге my_catalog :

CREATE OR REPLACE FUNCTION my_catalog.my_schema.calculate_bmi(weight DOUBLE, height DOUBLE)
RETURNS DOUBLE
LANGUAGE SQL
RETURN
SELECT weight / (height * height);

Пользовательские функции Python в Unity Catalog используют операторы, заключённые между двойными знаками доллара ($$). Необходимо указать сопоставление типов данных. В следующем примере регистрируется пользовательская функция (UDF), которая вычисляет индекс массы тела.

CREATE OR REPLACE FUNCTION my_catalog.my_schema.calculate_bmi(weight_kg DOUBLE, height_m DOUBLE)
RETURNS DOUBLE
LANGUAGE PYTHON
AS $$
return weight_kg / (height_m ** 2)
$$;

Теперь эту функцию каталога Unity можно использовать в запросах SQL или коде PySpark:

SELECT person_id, my_catalog.my_schema.calculate_bmi(weight_kg, height_m) AS bmi
FROM person_data;

Примеры фильтров строк и примеры маски столбцов см. в дополнительных примерах UDF.

Расширение UDF с использованием пользовательских зависимостей

Внимание

Эта функция доступна в общедоступной предварительной версии.

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

Вы можете расширить возможности Python UDF в Unity Catalog за пределами среды Databricks Runtime, определив пользовательские зависимости для внешних библиотек.

Требования

Пользовательские зависимости для определяемых пользователем функций (UDF) каталога Unity поддерживаются на следующих типах вычислительных ресурсов:

  • Бессерверные записные книжки и задания
  • Классические универсальные вычислительные ресурсы с использованием Databricks Runtime версии 16.2 и выше
  • Pro или бессерверное хранилище SQL

Источники зависимостей

Установите зависимости из следующих источников:

  • Пакеты PyPI
  • Файлы, хранящиеся в томах каталога Unity Пользователь, вызывающий UDF, должен иметь READ VOLUME разрешения на исходный том.
  • Файлы, доступные на общедоступных URL-адресах Правила безопасности сети рабочей области должны разрешать доступ к общедоступным URL-адресам. См. раздел Требования.

Примечание.

Если рабочая область ограничивает бессерверный сетевой доступ, необходимо настроить правила безопасности сети, чтобы разрешить общедоступные URL-адреса. См. «Настройка правил исходящего трафика».

Определение зависимостей

Используйте раздел ENVIRONMENT определения UDF, чтобы указать зависимости:

CREATE OR REPLACE FUNCTION my_catalog.my_schema.mixed_process(data STRING)
RETURNS STRING
LANGUAGE PYTHON
ENVIRONMENT (
  dependencies = '["simplejson==3.19.3", "/Volumes/my_catalog/my_schema/my_volume/packages/custom_package-1.0.0.whl", "https://my-bucket.s3.amazonaws.com/packages/special_package-2.0.0.whl?Expires=2043167927&Signature=abcd"]',
  environment_version = '3'
)
AS $$
import simplejson as json
import custom_package
return json.dumps(custom_package.process(data))
$$;

В разделе ENVIRONMENT содержатся следующие поля:

Поле Описание Тип Пример использования
dependencies Список зависимостей, разделенных запятыми для установки. Каждая запись — это строка, которая соответствует формату файла требований pip . STRING dependencies = '["simplejson==3.19.3", "/Volumes/catalog/schema/volume/packages/my_package-1.0.0.whl"]'
dependencies = '["https://my-bucket.s3.amazonaws.com/packages/my_package-2.0.0.whl?Expires=2043167927&Signature=abcd"]'
environment_version Указывает версию бессерверной среды, в которой выполняется UDF. Версия с фиксированной средой запускает UDF с определенной версией Python и набором предварительно установленных пакетов независимо от версии Python и пакетов в базовой среде Databricks Runtime.
Поддерживаемые значения: None или версия среды 3 и выше. Версии среды, кроме None, поддерживаются только в бессерверных вычислениях и бессерверных хранилищах SQL. Список доступных версий см. в разделе Версии среды.
STRING environment_version = '3'

Использовать функции, определяемые пользователем (UDF) каталога Unity в PySpark

from pyspark.sql.functions import expr

result = df.withColumn("bmi", expr("my_catalog.my_schema.calculate_bmi(weight_kg, height_m)"))
display(result)

Обновление UDF, относящегося к области сеанса

Примечание.

Синтаксис и семантика для пользовательских функций UDF на Python в каталоге Unity отличаются от пользовательских функций UDF на Python, зарегистрированных в SparkSession. См. определяемые пользователем скалярные функции — Python.

Учитывая следующую сессионную UDF в записной книжке Azure Databricks:

from pyspark.sql.functions import udf
from pyspark.sql.types import StringType

@udf(StringType())
def greet(name):
    return f"Hello, {name}!"

# Using the session-based UDF
result = df.withColumn("greeting", greet("name"))
result.show()

Чтобы зарегистрировать эту функцию в качестве функции каталога Unity, используйте инструкцию SQL CREATE FUNCTION, как показано в следующем примере:

CREATE OR REPLACE FUNCTION my_catalog.my_schema.greet(name STRING)
RETURNS STRING
LANGUAGE PYTHON
AS $$
return f"Hello, {name}!"
$$

Предоставление общего доступа к определяемым пользователем функциям в каталоге Unity

Элементы управления доступом, применяемые к каталогу, схеме или базе данных, где регистрируется UDF, управляют его разрешениями. Дополнительные сведения см. в разделе "Управление привилегиями" в каталоге Unity .

Используйте SQL Azure Databricks или пользовательский интерфейс рабочей области Azure Databricks, чтобы предоставить разрешения пользователю или группе (рекомендуется).

Разрешения в пользовательском интерфейсе рабочей области

  1. Найдите каталог и схему, в которой хранится UDF, и выберите UDF.
  2. Найдите параметр "Разрешения" в параметрах UDF. Добавьте пользователей или группы и укажите тип доступа, который они должны иметь, например EXECUTE или MANAGE.

Разрешения в пользовательском интерфейсе рабочей области

Разрешения с помощью Azure Databricks SQL

В следующем примере пользователь предоставляет пользователю разрешение EXECUTE на функцию:

GRANT EXECUTE ON FUNCTION my_catalog.my_schema.calculate_bmi TO `user@example.com`;

Чтобы удалить разрешения, используйте команду REVOKE, как показано в следующем примере:

REVOKE EXECUTE ON FUNCTION my_catalog.my_schema.calculate_bmi FROM `user@example.com`;

Изоляция среды

Примечание.

Для общих сред изоляции требуется Databricks Runtime 18.0 и более поздней версии. В более ранних версиях все пользовательские функции определения Python в Unity Catalog выполняются в строгом режиме изоляции.

Определяемые пользователем UDFS каталога Unity с тем же владельцем и сеансом могут совместно использовать среду изоляции по умолчанию. Это повышает производительность и сокращает использование памяти, уменьшая количество отдельных сред, которые необходимо запустить.

Строгая изоляция

Чтобы убедиться, что UDF всегда выполняется в собственной, полностью изолированной среде, добавьте STRICT ISOLATION предложение характеристик.

Большинству определяемых пользователем функций не требуется строгая изоляция. Стандартные UDF обработки данных используют общую среду изоляции по умолчанию и с меньшим потреблением памяти выполняются быстрее.

Добавьте характеристическую конструкцию в определяемые пользователем функции STRICT ISOLATION, которые:

  • Выполнение входных данных как кода с помощью функций eval(), exec() или аналогичных.
  • Запись файлов в локальную файловую систему.
  • Изменение глобальных переменных или состояния системы.
  • Доступ или изменение переменных среды.

В следующем коде показан пример UDF, который должен выполняться с помощью STRICT ISOLATION. Этот UDF выполняет произвольный Python код, поэтому может изменить состояние системы, получить доступ к переменным среды или записать в локальную файловую систему. Использование условия STRICT ISOLATION помогает предотвратить помехи или утечки данных в пользовательских определенных функциях (UDF).

CREATE OR REPLACE TEMPORARY FUNCTION run_python_snippet(python_code STRING)
RETURNS STRING
LANGUAGE PYTHON
STRICT ISOLATION
AS $$
import sys
from io import StringIO

# Capture standard output and error streams
captured_output = StringIO()
captured_errors = StringIO()
sys.stdout = captured_output
sys.stderr = captured_errors

try:
    # Execute the user-provided Python code in an empty namespace
    exec(python_code, {})
except SyntaxError:
    # Retry with escaped characters decoded (for cases like "\n")
    def decode_code(raw_code):
        return raw_code.encode('utf-8').decode('unicode_escape')
    python_code = decode_code(python_code)
    exec(python_code, {})

# Return everything printed to stdout and stderr
return captured_output.getvalue() + captured_errors.getvalue()
$$

Задайте DETERMINISTIC, если функция выдает последовательные результаты

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

По умолчанию Azure Databricks считает пакетные UDF Python в Unity Catalog недетерминированными, если вы явно не укажете иное. Примеры недетерминированных функций включают создание случайных значений, доступ к текущим времени или датам или вызовы внешних API.

См. CREATE FUNCTION (SQL, Python, Scala и Java)

Пользовательские функции для инструментов агента

ИИ-агенты могут использовать пользовательские функции (UDF) в Unity Catalog в качестве инструментов для выполнения задач и запуска пользовательской логики.

См. статью "Создание средств агента с помощью функций каталога Unity".

Пользовательские определенные функции (UDFs) для доступа к внешним API

Вы можете использовать функции, определяемые пользователем, для доступа к внешним API из SQL. В следующем примере библиотека Python requests используется для выполнения HTTP-запроса.

Примечание.

Пользовательские функции Python разрешают сетевой трафик TCP/UDP через порты 80, 443 и 53 при использовании бессерверных вычислений или вычислений, настроенных в стандартном режиме доступа.

CREATE FUNCTION my_catalog.my_schema.get_food_calories(food_name STRING)
RETURNS DOUBLE
LANGUAGE PYTHON
AS $$
import requests

api_url = f"https://example-food-api.com/nutrition?food={food_name}"
response = requests.get(api_url)

if response.status_code == 200:
   data = response.json()
   # Assume the API returns a JSON object with a 'calories' field
   calories = data.get('calories', 0)
   return calories
else:
   return None  # API request failed

$$;

Определяемые пользователем функции для обеспечения безопасности и соответствия требованиям

Используйте пользовательские функции Python для реализации кастомной токенизации, маскирования данных, редакции данных или шифрования.

В следующем примере идентификатор адреса электронной почты маскируется при сохранении длины и домена:

CREATE OR REPLACE FUNCTION my_catalog.my_schema.mask_email(email STRING)
RETURNS STRING
LANGUAGE PYTHON
DETERMINISTIC
AS $$
parts = email.split('@', 1)
if len(parts) == 2:
  username, domain = parts
else:
  return None
masked_username = username[0] + '*' * (len(username) - 2) + username[-1]
return f"{masked_username}@{domain}"
$$

В следующем примере применяется этот UDF в определении динамического представления:

-- First, create the view
CREATE OR REPLACE VIEW my_catalog.my_schema.masked_customer_view AS
SELECT
  id,
  name,
  my_catalog.my_schema.mask_email(email) AS masked_email
FROM my_catalog.my_schema.customer_data;

-- Now you can query the view
SELECT * FROM my_catalog.my_schema.masked_customer_view;
+---+------------+------------------------+------------------------+
| id|        name|                   email|           masked_email |
+---+------------+------------------------+------------------------+
|  1|    John Doe|   john.doe@example.com |  j*******e@example.com |
|  2| Alice Smith|alice.smith@company.com |a**********h@company.com|
|  3|   Bob Jones|    bob.jones@email.org |   b********s@email.org |
+---+------------+------------------------+------------------------+

Лучшие практики

Чтобы UDF были доступны всем пользователям, Databricks рекомендует создать выделенный каталог и схему с соответствующими механизмами управления доступом.

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

Databricks рекомендует включить в документ UDF следующие сведения:

  • Номер текущей версии
  • Журнал изменений для отслеживания изменений в разных версиях
  • Назначение, параметры и возвращаемое значение UDF
  • Пример использования UDF

В следующем примере показана UDF, которая соответствует лучшим практикам.

CREATE OR REPLACE FUNCTION my_catalog.my_schema.calculate_bmi(weight_kg DOUBLE, height_m DOUBLE)
RETURNS DOUBLE
COMMENT "Calculates Body Mass Index (BMI) from weight and height."
LANGUAGE PYTHON
DETERMINISTIC
AS $$
 """
Parameters:
calculate_bmi (version 1.2):
- weight_kg (float): Weight of the individual in kilograms.
- height_m (float): Height of the individual in meters.

Returns:
- float: The calculated BMI.

Example Usage:

SELECT calculate_bmi(weight, height) AS bmi FROM person_data;

Change Log:
- 1.0: Initial version.
- 1.1: Improved error handling for zero or negative height values.
- 1.2: Optimized calculation for performance.

 Note: BMI is calculated as weight in kilograms divided by the square of height in meters.
 """
if height_m <= 0:
 return None  # Avoid division by zero and ensure height is positive
return weight_kg / (height_m ** 2)
$$;

Поведение часового пояса метки времени для входных данных

В Databricks Runtime 18.0 и более поздних версиях при передаче значений TIMESTAMP в пользовательские функции Python (UDF) значения остаются в UTC. datetime Однако объект не включает метаданные часового пояса (tzinfoатрибут).

Это изменение согласует Python UDFs в каталоге Unity с оптимизированными с помощью Arrow Python UDFs в Apache Spark.

Например, следующий запрос:

CREATE FUNCTION timezone_udf(date TIMESTAMP)
RETURNS STRING
LANGUAGE PYTHON
AS $$
return f"{type(date)} {date} {date.tzinfo}"
$$;

SELECT timezone_udf(TIMESTAMP '2024-10-23 10:30:00');

Ранее выдали эти выходные данные в версиях Databricks Runtime до 18.0:

<class 'datetime.datetime'> 2024-10-23 10:30:00+00:00 Etc/UTC

В Databricks Runtime 18.0 и более поздних версиях теперь он создает следующие выходные данные:

<class 'datetime.datetime'> 2024-10-23 10:30:00+00:00 None

Если ваша UDF зависит от информации о часовом поясе, необходимо явно восстановить эти сведения:

from datetime import timezone

date = date.replace(tzinfo=timezone.utc)

Ограничения

  • Вы можете определить любое количество функций Python в UDF Python, но все они должны возвращать скалярное значение.
  • Функции Python должны обрабатывать значения NULL независимо, и все сопоставления типов должны соответствовать сопоставлениям языков SQL Azure Databricks.
  • Если вы не указываете каталог или схему, Azure Databricks регистрирует пользовательские функции Python в текущей активной схеме.
  • Пользовательские функции Python (UDF) выполняются в защищённой, изолированной среде и не имеют доступа к файловым системам или внутренним сервисам.
  • Вы не можете вызывать более пяти определяемых пользователем функций в каждом запросе.