Usar funções de dados de utilizador em Fabric Data Warehouse (pré-visualização)

Aplica-se para:✅ Armazém no Microsoft Fabric

Importante

Este recurso está em pré-visualização.

No Fabric Data Warehouse, os programadores de T-SQL podem chamar funções de dados do utilizador do Fabric a partir de consultas T-SQL. Uma função proxy T-SQL num armazém de dados chama a função Python referenciada num item publicado de funções de dados do utilizador.

Use esta integração para estender o T-SQL com lógica Python reutilizável para cenários como:

  • Utilização de pacotes especializados PyPI para cargas de trabalho espaciais, numéricas ou de ciência de dados.
  • Implementar lógica de negócio personalizada em Python.
  • Invocar APIs externas.
  • Interagir com outros itens do Fabric e serviços do Azure, como warehouses, lakehouses, bases de dados SQL ou uma Cosmos DB.

Diagrama que mostra como o armazém de dados interage com uma Função de Dados de Utilizador do Fabric, invocando uma U D F através de uma função proxy do armazém de dados.

Este artigo mostra como referenciar uma função de dados de utilizador publicada a partir de Fabric Data Warehouse e utilizá-la em consultas T-SQL.

Pré-requisitos

Para utilizar as funções de dados do utilizador a partir de Fabric Data Warehouse, precisa de:

Criar e publicar uma função de dados de utilizador

Antes de poder chamar uma função de dados de utilizador a partir de um armazém, crie e publique a função num item de funções de dados de utilizador. Para passos completos e funções de exemplo em Python, consulte Criar um item de funções de dados de utilizador no Fabric.

Uma função de dados de utilizador em Python que poderia criar é mostrada no seguinte exemplo:

import fabric.functions as fn

udf = fn.UserDataFunctions()

@udf.function()
def hello_fabric(name: str) -> str:
    # Your function logic here
    return name

Usas o nome do item da função de dados de utilizador para associar uma função proxy T-SQL à função Python.

Criar uma função proxy T-SQL

Crie uma função T-SQL no seu armazém e associe-a à função Python publicada usando a AS EXTERNAL FUNCTION cláusula.

CREATE OR ALTER FUNCTION dbo.hello_fabric
AS EXTERNAL FUNCTION FunctionSetName.hello_fabric;

Substitua FunctionSetName pelo nome do item de funções de dados do utilizador e hello_fabric pelo nome da função Python publicada.

Sugestão

Pode gerar o código de invocação a partir da experiência das funções de dados do utilizador e usá-lo como ponto de partida para a função proxy do armazém.

Por defeito, a instrução CREATE FUNCTION infere a lista de parâmetros e o tipo de retorno a partir da definição da Fabric User Data Function (UDF) remota. Pode sobrescrever o tipo de retorno inferido especificando-o explicitamente na definição da função. Fornecer o tipo de retorno é útil quando se pretende expor um tipo de retorno mais preciso do que o tipo inferido a partir dos metadados da função remota.

CREATE OR ALTER FUNCTION dbo.hello_fabric
RETURNS VARCHAR(100)
AS EXTERNAL FUNCTION FunctionSetName.hello_fabric;

Por exemplo, um valor de retorno em Python str é tipicamente inferido como VARCHAR(MAX), mas se a função devolver sempre um valor com um comprimento máximo conhecido, pode definir explicitamente o tipo de retorno como VARCHAR(100) ou outro comprimento apropriado para fornecer metadados e informação de tipo mais precisas.

Usar funções proxy em consultas T-SQL

Depois de criares a função proxy, chama-a a partir do T-SQL como qualquer outra função definida pelo utilizador.

Use a função proxy em expressões de consulta como:

  • SELECT listas.
  • WHERE cláusulas.
  • GROUP BY cláusulas.
  • Expressões em instruções UPDATE e INSERT.

O padrão seguinte mostra como chamar uma função proxy a partir de uma consulta:

SELECT dbo.<proxy_function_name>(<arguments>) AS function_result;

Para padrões avançados em Python, tipos suportados, ligações e objetos de contexto, veja a visão geral do modelo de programação de funções de utilizador do Fabric.

Configurar a execução em modo batch

Fabric Data Warehouse pode executar funções de dados de utilizador externos em modo batch.

A execução em modo batch envia múltiplas invocações de funções num único pedido para o serviço remoto Fabric User Data Function (UDF), reduzindo a sobrecarga da rede e a latência dos pedidos. Um lote pode conter até 900 chamadas de função.

O modo batch é tipicamente usado quando a mesma função é aplicada a valores de uma ou mais colunas da tabela, permitindo ao processador de consultas avaliar muitas linhas numa única chamada remota em vez de emitir um pedido separado para cada linha. Este método pode melhorar significativamente o desempenho das consultas, especialmente para conjuntos de dados grandes e chamadas de funções externas de alta latência.

Por exemplo, quando uma consulta aplica uma função de dados de utilizador a cada valor de uma coluna, Fabric Data Warehouse pode agrupar os valores de entrada em lotes e submetê-los juntos para processamento remoto. O serviço remoto devolve um lote correspondente de resultados, que são então integrados no pipeline de execução da consulta.

Para ativar o modo batch para uma função de dados de utilizador:

  1. Abra o item de funções de dados do utilizador .
  2. Vá àsDefiniçõesde Gestão> da Biblioteca.
  3. Ativa as funcionalidades de Pré-visualização.

Defina max_batch_size=900 no decorador @udf.function() para permitir que o armazém de dados envie até 900 linhas de entrada em cada invocação:

Note

O argumento max_batch_size só está disponível quando a pré-visualização em modo batch está ativada.

import fabric.functions as fn

udf = fn.UserDataFunctions()

@udf.function(max_batch_size=900)
def normalizeText(value: str) -> str:
    return value.strip().lower()

Depois de criar uma função proxy T-SQL que referencia uma função de dados de utilizador (UDF) habilitada por lote, Fabric Data Warehouse deteta automaticamente a configuração em lote, incluindo o tamanho máximo de lote definido pela função remota. Quando o padrão de consulta suporta loteamento, o processador de consultas agrupa múltiplas invocações de funções em lotes e envia-as para o serviço remoto para execução, em vez de emitir pedidos individuais para cada linha.

Listar funções de dados de utilizador num armazém

As funções de dados do utilizador que criar com AS EXTERNAL FUNCTION aparecem em sys.objects com o tipo de objeto XF.

Para listar as funções de dados do utilizador num armazém, filtre sys.objects por type = 'XF'.

SELECT SCHEMA_NAME(schema_id) AS schema_name, name, object_id, type, type_desc
FROM sys.objects
WHERE type = 'XF';

Para listar tanto as funções escalares regulares (FN) como as funções de dados do utilizador (XF) juntamente com as suas assinaturas de parâmetros e tipos de retorno, use sys.parameters e sys.types:

WITH metadata AS
(
    SELECT o.schema_id, o.object_id, o.name, p.parameter_id, p.name AS parameter_name, t.name AS type_name
    FROM sys.objects AS o
    INNER JOIN sys.parameters AS p
        ON p.object_id = o.object_id
    INNER JOIN sys.types AS t
        ON t.user_type_id = p.user_type_id
    WHERE o.type IN ('FN', 'XF')
),
signature AS
(
    SELECT SCHEMA_NAME(schema_id) AS schema_name,
           name,
           ANY_VALUE(
               CASE WHEN parameter_id = 0 THEN type_name END
           ) AS return_type,
           CONCAT(
               SCHEMA_NAME(schema_id),
               '.',
               name,
               '(',
               STRING_AGG(
                   CASE
                       WHEN parameter_id > 0
                       THEN CONCAT(parameter_name, ' ', type_name)
                   END,
                   ', '
               ) WITHIN GROUP (ORDER BY parameter_id),
               ') -> ',
               MAX(CASE WHEN parameter_id = 0 THEN type_name END)
           ) AS signature
    FROM metadata
    GROUP BY schema_id, object_id, name
)
SELECT *
FROM signature;

Remarks

Examples

Os cenários seguintes mostram formas comuns de estender Fabric Data Warehouse com funções de dados do utilizador.

A. Estender T-SQL com análise de endereços IP

Use uma função de dados de utilizador em Python quando a sua consulta de armazém precisar de funcionalidades que não estejam disponíveis como função T-SQL incorporada. Por exemplo, pode usar um pacote de endereços IP para obter a sub-rede correspondente a um endereço IP. Pode aplicar esta função em lotes quando uma consulta processa endereços IP de várias linhas. Para os passos de configuração, veja Configurar o modo batch.

Note

Se a função usar um pacote que não faz parte da biblioteca padrão Python, adicione o pacote na gestão de bibliotecas antes de publicar o item da função de dados do utilizador. Este exemplo utiliza o netaddr pacote.

Defina e publique a função Python num item de função de dados do utilizador:

from netaddr import IPNetwork
import fabric.functions as fn

udf = fn.UserDataFunctions()

@udf.function(max_batch_size=900)
def ipSubnet(ipAddress: str, prefixLength: int = 24) -> str:
    return str(IPNetwork(f"{ipAddress}/{prefixLength}").cidr)

Crie uma função proxy T-SQL no armazém que faça referência à função Python publicada:

CREATE OR ALTER FUNCTION dbo.ip_subnet
AS EXTERNAL FUNCTION inet.ipSubnet;

Invocar a função de proxy a partir de uma consulta ao armazém de dados:

SELECT dbo.ip_subnet('192.168.1.25', 24) AS subnet;

Resultado esperado:192.168.1.0/24

B. Invocar uma API pública externa

Use uma função de dados de utilizador quando uma consulta de armazém precisar de chamar uma API externa como parte de um fluxo de trabalho de enriquecimento de dados.

Na base de dados SQL do Fabric, na Base de Dados SQL do Azure e na Instância Gerida de SQL do Azure, sys.sp_invoke_external_rest_endpoint invoca um ponto final REST HTTPS. Em Fabric Data Warehouse, uma função de dados do utilizador pode fornecer um padrão alternativo ao envolver uma chamada HTTPS em Python e expô-la a T-SQL através de uma função proxy.

Caution

Chamar um endpoint externo pode transferir dados para fora do seu armazém de dados. Use endpoints aprovados, evite enviar dados sensíveis a menos que autorizado e cumpra os requisitos de segurança e conformidade da sua organização.

Note

Adicione bibliotecas de terceiros obrigatórias, como requests, na gestão de bibliotecas antes de publicar a função.

Defina e publique a função Python num item de funções de dados do utilizador. Este exemplo utiliza nomes de parâmetros semelhantes a sys.sp_invoke_external_rest_endpoint:

import json
import requests
import fabric.functions as fn

udf = fn.UserDataFunctions()

@udf.function()
def invokeExternalRestEndpoint(
    url: str,
    method: str = "GET",
    payload: str | None = None,
    headers: str | None = None,
    timeout: int = 30
) -> str:
    requestHeaders = json.loads(headers) if headers else None
    requestPayload = payload if payload else None

    response = requests.request(
        method=method,
        url=url,
        data=requestPayload,
        headers=requestHeaders,
        timeout=timeout
    )
    response.raise_for_status()
    return response.text

Crie uma função proxy T-SQL no armazém:

CREATE OR ALTER FUNCTION dbo.invoke_external_rest_endpoint
AS EXTERNAL FUNCTION api.invokeExternalRestEndpoint;

Chame a função de proxy numa consulta ao armazém de dados:

SELECT dbo.invoke_external_rest_endpoint(
    'https://ipapi.co/8.8.8.8/country_name/',
    'GET',
    NULL,
    NULL,
    30
) AS response;

C. Use um período de retenção configurável

Use uma função de dados de utilizador quando as consultas de armazém necessitem de valores de configuração geridos centralmente a partir de uma biblioteca de variáveis Fabric. Por exemplo, armazenar um período de retenção na biblioteca de variáveis, recuperá-lo através de uma função proxy e usá-lo como argumento numérico da DATEADD função T-SQL.

Antes de publicar a função, adicione uma ligação do item das funções de dados do utilizador à biblioteca de variáveis e anote o alias de ligação. A biblioteca de variáveis neste exemplo contém um RETENTION_DAYS valor como 90.

Defina e publique a função Python num item de função de dados do utilizador:

import fabric.functions as fn

udf = fn.UserDataFunctions()

@udf.connection(argName="varLib", alias="WarehouseConfig")
@udf.function()
def getRetentionDays(varLib: fn.FabricVariablesClient) -> int:
    variables = varLib.getVariables()
    return int(variables["RETENTION_DAYS"])

Substitui WarehouseConfig pelo alias da ligação à tua biblioteca de variáveis.

Crie uma função proxy T-SQL no armazém:

CREATE OR ALTER FUNCTION dbo.get_retention_days
AS EXTERNAL FUNCTION config.getRetentionDays;

Numa ligação T-SQL persistente, recupere o valor configurado uma vez e armazene-o usando sp_set_session_context:

DECLARE @retention_days int = dbo.get_retention_days();

EXECUTE sys.sp_set_session_context
    @key = N'retention_days',
    @value = @retention_days,
    @read_only = 1;

O valor permanece disponível durante toda a duração da sessão. Recupera-o com SESSION_CONTEXT e converte-o de sql_variant para int antes de o utilizar com DATEADD e GETDATE. Por exemplo, calcule um corte de retenção:

SELECT DATEADD(
    day,
    -CONVERT(int, SESSION_CONTEXT(N'retention_days')),
    GETDATE()
) AS retention_cutoff;

Reutilize o mesmo valor de sessão noutra instrução para filtrar uma tabela:

SELECT *
FROM dbo.events
WHERE event_timestamp >= DATEADD(
    day,
    -CONVERT(int, SESSION_CONTEXT(N'retention_days')),
    GETDATE()
);

Importante

Utilize este padrão de um cliente que mantenha uma ligação T-SQL persistente, como o SQL Server Management Studio ou a extensão MSSQL para Visual Studio Code. O editor de consultas SQL no portal Fabric não suporta sp_set_session_context, e cada execução usa uma sessão separada. Para mais informações, consulte limitações do editor de consultas SQL.

Resolver problemas das funções de dados do utilizador

O Query Insights fornece a informação de execução e desempenho necessária para diagnosticar funções do Fabric. Pode identificar consultas que invocaram uma função, determinar se a função usou execução por lote ou por linha, e investigar a latência de serviço externo, tentativas, linhas falhadas e o tamanho da carga útil. Use as seguintes duas vistas para passar de uma visão geral ao nível da consulta para estatísticas detalhadas para cada função:

  • queryinsights.exec_requests_history Use para identificar consultas que invocaram funções de Fabric ou IA. A visualização inclui o texto da consulta, estado, tempo de submissão e tempo total decorrido.
  • queryinsights.external_api_call_stats Use para obter estatísticas detalhadas para cada função invocada por uma consulta. A visualização inclui o tipo de função, o modo de execução, a contagem de chamadas e de novas tentativas, o tempo de espera do serviço externo, o tamanho da carga útil e os resultados por linha.

As vistas usam distributed_statement_id para identificar a execução da mesma consulta.

Encontre consultas que usaram funções Fabric

Use queryinsights.exec_requests_history para encontrar declarações recentes que invocaram uma função Fabric ou IA:

SELECT TOP 100
       h.distributed_statement_id,
       h.submit_time,
       h.status,
       h.total_elapsed_time_ms,
       h.command
FROM queryinsights.exec_requests_history AS h
WHERE h.is_using_external_api = 1
ORDER BY h.submit_time DESC;

Copie o distributed_statement_id da declaração que pretende investigar. A consulta seguinte filtra as estatísticas detalhadas para funções Fabric.

Ver estatísticas para cada função numa instrução

Substitua <distributed_statement_id> por um identificador devolvido pela consulta anterior. A consulta seguinte devolve uma linha para cada função Fabric distinta invocada pela afirmação:

DECLARE @distributed_statement_id uniqueidentifier =
    '<distributed_statement_id>';

SELECT function_name,
       execution_mode,
       call_count,
       batch_call_count,
       row_call_count,
       call_retry_count,
       external_service_wait_time_ms,
       external_service_wait_time_ms
           / call_count AS average_wait_time_ms_per_call,
       rows_total,
       rows_succeeded,
       rows_failed,
       data_sent_bytes,
       data_received_bytes
FROM queryinsights.external_api_call_stats
WHERE distributed_statement_id = @distributed_statement_id
  AND function_type = 'FABRIC_FUNCTION'
ORDER BY external_service_wait_time_ms DESC;

Os resultados assemelham-se ao seguinte exemplo:

function_name execution_mode call_count batch_call_count row_call_count número_de_tentativas_de_repetição_de_chamada tempo_de_espera_do_serviço_externo_ms tempo_medio_de_espera_ms_por_chamada rows_total linhas_com_sucesso rows_failed data_sent_bytes dados_recebidos_bytes
inet.ipSubnet batch 12 12 0 0 840 70 600 600 0 12,000 9,600
api.invokeExternalRestEndpoint row 4 0 4 1 1 920 480 4 4 0 1,024 512

Sugestões de resolução de problemas

  • Um valor alto de row_call_count ou um valor de execution_mode de row pode indicar que a função não está a usar execução em lote. Se esperares processamento em lote, confirma que a pré-visualização do modo em lote está ativada e que a função usa o argumento max_batch_size.
  • Use external_service_wait_time_ms e average_wait_time_ms_per_call identifique respostas externas lentas. Se estes valores forem altos e data_sent_bytesdata_received_bytes baixos, o tempo de resposta do serviço externo é provavelmente o atraso principal.
  • Valores grandes data_sent_bytesdata_received_bytes também podem aumentar o tempo de execução. Reduzir a carga útil de entrada ou saída se a função transferir mais dados do que o cenário exige.