Partilhar via


Funções definidas pelo usuário (UDFs) no Unity Catalog

Importante

Esta funcionalidade está em Pré-visualização Pública.

As funções definidas pelo usuário (UDFs) no Unity Catalog estendem os recursos SQL e Python no Azure Databricks. Eles permitem que funções personalizadas sejam definidas, usadas e compartilhadas e controladas com segurança em ambientes de computação.

UDFs de Python registradas como funções no Unity Catalog diferem no âmbito e no suporte das UDFs PySpark com escopo para um bloco de notas ou SparkSession. Consulte Funções escalares definidas pelo usuário - Python.

Consulte CREATE FUNCTION (SQL e Python) para obter a referência completa da linguagem SQL.

Requisitos

Para usar UDFs no Unity Catalog, você deve atender aos seguintes requisitos:

  • Para usar o código Python em UDFs registradas no Unity Catalog, você deve usar um armazém SQL sem servidor ou pro ou um cluster executando o Databricks Runtime 13.3 LTS ou superior.
  • Se uma vista incluir um UDF Python do Unity Catalog, irá falhar nos armazéns SQL clássicos.

Criando UDFs no Unity Catalog

Para criar um UDF no Unity Catalog, os utilizadores precisam das permissões USAGE e CREATE no esquema e USAGE no catálogo. Consulte o Unity Catalog para obter mais detalhes.

Para executar um UDF, os usuários precisam da permissão EXECUTE no UDF. Os utilizadores também precisam da permissão USAGE no esquema e no catálogo.

Para criar e registrar um UDF em um esquema de catálogo Unity, o nome da função deve seguir o formato catalog.schema.function_name. Como alternativa, você pode selecionar o catálogo e o esquema corretos no Editor SQL. Neste caso, o nome da sua função não deve ter catalog.schema sido precedido:

Criação de um UDF com o catálogo e o esquema pré-selecionados.

O exemplo a my_schema seguir registra uma nova função para o my_catalog esquema no catálogo:

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

UDFs Python para o Unity Catalog usam declarações delimitadas por cifrões duplos ($$). Você deve especificar um mapeamento de tipo de dados. O exemplo seguinte regista um UDF que calcula o índice de massa corporal:

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)
$$;

Agora você pode usar esta função Unity Catalog em suas consultas SQL ou código PySpark:

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

Consulte Exemplos de filtro de linha e Exemplos de máscara de coluna para obter mais exemplos de UDF.

Estender UDFs usando dependências personalizadas

Importante

Esta funcionalidade está em Pré-visualização Pública.

Estenda a funcionalidade das UDFs Python do Unity Catalog para além do ambiente Databricks Runtime definindo dependências personalizadas para bibliotecas externas.

Instale dependências das seguintes fontes:

  • Pacotes PyPI
  • Arquivos armazenados em volumes do Catálogo Unity O usuário que invoca o UDF deve ter permissões de READ VOLUME no volume de origem.
  • Arquivos disponíveis em URLs públicas As regras de segurança de rede do espaço de trabalho devem permitir o acesso a URLs públicas.

Nota

Para configurar regras de segurança de rede para permitir o acesso a URLs públicas de um SQL warehouse sem servidor, consulte Validar com Databricks SQL.

  • Os armazéns SQL sem servidor exigem o recurso de visualização pública Habilite a rede para UDFs em SQL Warehouses sem servidor para ser habilitada na página Visualizações do seu espaço de trabalho para acessar a Internet para dependências personalizadas.

As dependências personalizadas para UDFs do Unity Catalog são suportadas nos seguintes tipos de computação:

  • Blocos de anotações e trabalhos sem servidor
  • Computação multiuso usando o Databricks Runtime versão 16.2 e superior
  • Armazém SQL profissional ou sem servidor

Use a seção ENVIRONMENT da definição UDF para especificar dependências:

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 = 'None'
)
AS $$
import simplejson as json
import custom_package
return json.dumps(custom_package.process(data))
$$;

A secção ENVIRONMENT contém os seguintes campos:

Campo Descrição Tipo Exemplo de utilização
dependencies Uma lista de dependências separadas por vírgulas para instalar. Cada entrada é uma cadeia de caracteres que está em conformidade com o pip Requirements File Format. 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 Especifica a versão do ambiente sem servidor na qual executar o UDF.
Atualmente, apenas o valor None é suportado.
STRING environment_version = 'None'

Use UDFs do catálogo Unity no PySpark

from pyspark.sql.functions import expr

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

Atualizar uma UDF definida no escopo da sessão

Nota

A sintaxe e a semântica das UDFs Python no Unity Catalog diferem das UDFs Python registadas no SparkSession. Consulte funções escalares definidas pelo usuário - Python.

Dada a seguinte UDF baseada em sessão num notebook do 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()

Para registrar isso como uma função Unity Catalog, use uma instrução SQL CREATE FUNCTION, como no exemplo a seguir:

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

Compartilhar UDFs no Unity Catalog

As permissões para UDFs são gerenciadas com base nos controles de acesso aplicados ao catálogo, esquema ou banco de dados onde o UDF está registrado. Consulte Gerenciar privilégios no Catálogo Unity para obter mais informações.

Use o Azure Databricks SQL ou a interface do usuário do espaço de trabalho do Azure Databricks para conceder permissões a um usuário ou grupo (recomendado).

Permissões na interface do espaço de trabalho

  1. Encontre o catálogo e o esquema onde o UDF está armazenado e selecione o UDF.
  2. Procure uma opção Permissões nas configurações UDF. Adicione usuários ou grupos e especifique o tipo de acesso que eles devem ter, como EXECUTAR ou GERENCIAR.

permissões na UI de espaço de trabalho

Permissões usando o Azure Databricks SQL

O exemplo a seguir concede a um usuário a permissão EXECUTE em uma função:

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

Para remover permissões, use o comando REVOKE como no exemplo a seguir:

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

Isolamento do ambiente

Nota

Ambientes de isolamento partilhado requerem Databricks Runtime 18.0 e superiores. Em versões anteriores, todos os UDFs Python do Unity Catalog corriam em modo de isolamento estrito.

Os Python UDFs no Unity Catalog com o mesmo proprietário e sessão podem partilhar um ambiente de isolamento por padrão. Isso melhora o desempenho e reduz o uso de memória, reduzindo o número de ambientes separados que precisam ser iniciados.

Isolamento rigoroso

Para garantir que uma UDF seja sempre executada em seu próprio ambiente totalmente isolado, adicione a STRICT ISOLATION cláusula característica.

A maioria das UDFs não precisa de isolamento estrito. As UDFs de processamento de dados padrão se beneficiam do ambiente de isolamento compartilhado padrão e são executadas mais rapidamente com menor consumo de memória.

Adicione a STRICT ISOLATION cláusula característica aos UDF que:

  • Execute a entrada como código usando eval(), exec()ou funções semelhantes.
  • Grave arquivos no sistema de arquivos local.
  • Modifique as variáveis globais ou o estado do sistema.
  • Acesse ou modifique variáveis de ambiente.

O código seguinte mostra um exemplo de um UDF que deve ser executado usando STRICT ISOLATION. Este UDF executa código Python arbitrário, pelo que pode alterar o estado do sistema, aceder a variáveis de ambiente ou escrever no sistema de ficheiros local. A utilização da STRICT ISOLATION cláusula ajuda a prevenir interferências ou fugas de dados entre UDFs.

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()
$$

Definir DETERMINISTIC se a sua função produz resultados consistentes

Adicione DETERMINISTIC à sua definição de função se ela produzir as mesmas saídas para as mesmas entradas. Isso permite otimizações de consulta para melhorar o desempenho.

Por padrão, as UDFs Python do Batch Unity Catalog são consideradas não determinísticas, a menos que explicitamente declaradas. Exemplos de funções não determinísticas incluem gerar valores aleatórios, acessar horas ou datas atuais ou fazer chamadas de API externas.

Veja CREATE FUNCTION (SQL e Python)

UDFs para ferramentas de agente de IA

Os agentes de IA generativa podem usar UDFs do Unity Catalog como ferramentas para executar tarefas e executar lógica personalizada.

Consulte Criar ferramentas de agente de IA usando funções do Unity Catalog.

UDFs para acessar APIs externas

Você pode usar UDFs para acessar APIs externas do SQL. O exemplo a seguir usa a biblioteca Python requests para fazer uma solicitação HTTP.

Nota

Os UDFs em Python permitem tráfego de rede TCP/UDP nas portas 80, 443 e 53 quando utilizam computação serverless ou computação configurada com modo de acesso padrão.

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

$$;

UDFs para segurança e conformidade

Use UDFs Python para implementar tokenização personalizada, mascaramento de dados, edição de dados ou mecanismos de criptografia.

O exemplo a seguir mascara a identidade de um endereço de e-mail enquanto mantém o comprimento e o domínio:

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}"
$$

O exemplo a seguir aplica essa UDF em uma definição de exibição dinâmica:

-- 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 |
+---+------------+------------------------+------------------------+

Melhores práticas

Para que as UDFs sejam acessíveis a todos os usuários, recomendamos a criação de um catálogo e esquema dedicados com controles de acesso apropriados.

Para UDFs específicas da equipe, use um esquema dedicado dentro do catálogo da equipe para armazenamento e gerenciamento.

O Databricks recomenda que você inclua as seguintes informações no docstring UDF:

  • O número da versão atual
  • Um changelog para controlar modificações entre versões
  • A finalidade, os parâmetros e o valor de retorno UDF
  • Um exemplo de como usar o UDF

Aqui está um exemplo de uma UDF seguindo as práticas recomendadas:

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)
$$;

Comportamento do fuso horário com carimbo temporal para entradas

No Databricks Runtime 18.0 e superiores, quando os valores TIMESTAMP são passados para UDFs em Python, os valores permanecem em UTC, mas os metadados do fuso horário (atributo tzinfo) não são incluídos no objeto datetime.

Esta alteração harmoniza os UDFs Python do Unity Catalog com os UDFs Python otimizados para Arrow no Apache Spark.

Por exemplo, a seguinte consulta:

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');

Anteriormente produziu esta saída em versões Databricks Runtime antes da 18.0:

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

No Databricks Runtime 18.0 e superiores, agora produz esta saída:

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

Se o seu UDF depende da informação do fuso horário, precisa de o restaurar explicitamente:

from datetime import timezone

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

Limitações

  • Você pode definir qualquer número de funções Python dentro de um Python UDF, mas todas devem retornar um valor escalar.
  • As funções Python devem manipular valores NULL de forma independente e todos os mapeamentos de tipo devem seguir os mapeamentos da linguagem SQL do Azure Databricks.
  • Se nenhum catálogo ou esquema for especificado, as UDFs Python serão registradas no esquema ativo atual.
  • As UDFs Python são executadas em um ambiente seguro e isolado e não têm acesso a sistemas de arquivos ou serviços internos.
  • Não é possível chamar mais de cinco UDFs por consulta.