Como criar UDFs de Python

Este tópico mostra como criar e instalar uma UDF (função definida pelo usuário) de Python.

Neste tópico:

Como escrever o código de Python

Como escrever o módulo e a função de Python

Escreva um módulo que siga as especificações abaixo:

  • Defina o módulo. Um módulo é um arquivo contendo definições e instruções de Python.

  • Defina uma função dentro do módulo.

  • Se a função aceitar argumentos, cada argumento deve ser um dos tipos de dados especificados na coluna Python Data Type da tabela de mapeamento entre tipos de SQL e Python.

    Os argumentos de função estão vinculados à posição, não ao nome. O primeiro argumento passado para a UDF é o primeiro argumento recebido pela função de Python.

  • Especifique um valor de retorno adequado. Como uma UDF de Python deve ser uma função escalar, ela deve retornar um valor cada vez que for invocada. O tipo do valor de retorno deve ser um dos tipos de dados especificados na coluna Python Data Type da tabela de mapeamento entre tipos de SQL e Python. O tipo do valor de retorno deve ser compatível com o tipo de dados de SQL especificado na cláusula RETURNS da instrução CREATE FUNCTION.

  • Seu módulo pode conter mais de uma função. A função que é chamada pelo Snowflake pode chamar outras funções no mesmo módulo ou em outros módulos.

  • Sua função (e quaisquer funções chamadas por sua função) devem estar de acordo com as restrições impostas pelo Snowflake para UDFs de Python.

Nota

As UDFs de Python vetorizadas permitem que você defina funções Python que recebem lotes de linhas de entrada como DataFrames do Pandas e retornam lotes de resultados como matrizes ou séries do Pandas. Para obter mais informações, consulte UDFs vetorizadas de Python.

Criação da função no Snowflake

Você deve executar uma instrução CREATE FUNCTION para especificar:

  • O nome a ser usado para a UDF.

  • O nome da função de Python a ser chamada quando a UDF de Python é chamada.

O nome da UDF não precisa corresponder ao nome da função do manipulador escrita em Python. A cláusula HANDLER na instrução CREATE FUNCTION associa o nome da UDF com a função de Python.

Ao escolher um nome para a UDF, consulte Como nomear e sobrecarregar procedimentos e UDFs.

Dentro do corpo da instrução CREATE FUNCTION, os argumentos da função são vinculados pela posição, não pelo nome. O primeiro argumento declarado na instrução CREATE FUNCTION é o primeiro argumento passado para a função de Python.

Para obter mais informações sobre os tipos de dados de argumentos, consulte Mapeamentos de tipos de dados SQL-Python.

Defina runtime_version como a versão do Python runtime que seu código requer. As versões suportadas do Python são:

  • 3.8

  • 3.9

  • 3,10

UDFs com código inline vs. UDFs com código carregado de um estágio

O código para uma UDF de Python pode ser especificado de uma das seguintes maneiras:

  • Carregado de um estágio: a instrução CREATE FUNCTION especifica a localização de um código-fonte de Python existente em um estágio.

  • Inline: a instrução CREATE FUNCTION especifica o código-fonte de Python.

Como criar uma UDF de Python inline

Para criar uma UDF inline, forneça o código-fonte de Python como parte da instrução CREATE FUNCTION.

Por exemplo, a seguinte instrução cria uma UDF de Python inline que adiciona um a um determinado número inteiro:

create or replace function addone(i int)
returns int
language python
runtime_version = '3.8'
handler = 'addone_py'
as
$$
def addone_py(i):
  return i+1
$$;
Copy

O código-fonte de Python é especificado na cláusula AS. O código-fonte pode ser colocado entre aspas simples ou entre um par de cifrões ($$). O uso dos cifrões geralmente é mais fácil se o código-fonte contiver aspas simples incorporadas.

Chame a UDF:

select addone(10);
Copy

Aqui está a saída:

+------------+
| ADDONE(10) |
|------------|
|         11 |
+------------+
Copy

O código-fonte de Python pode conter mais de um módulo, e mais de uma função em um módulo. Portanto, a cláusula HANDLER especifica o módulo e a função a ser chamada.

Uma UDF de Python inline pode chamar código em módulos que estão incluídos na cláusula IMPORTS.

Para obter mais detalhes sobre a sintaxe da instrução CREATE FUNCTION, consulte CREATE FUNCTION.

Para obter mais exemplos, consulte exemplos de UDF de Python inline.

Como criar uma UDF de Python com código carregado de um estágio

As instruções a seguir criam uma UDF de Python simples usando código carregado de um estágio. O estágio que hospeda o arquivo deve ser legível pelo proprietário da UDF. Além disso, arquivos ZIP devem ser autocontidos e não confiar em nenhum script de configuração adicional para serem executados.

Crie um arquivo de Python chamado sleepy.py contendo seu código-fonte:

def snore(n):   # return a series of n snores
    result = []
    for a in range(n):
        result.append("Zzz")
    return result
Copy

Inicie o comando SnowSQL (cliente CLI) e use o comando PUT para copiar o arquivo do sistema de arquivos local para o estágio padrão do usuário, chamado @~. (O comando PUT não pode ser executado pela GUI do Snowflake).

put
file:///Users/Me/sleepy.py
@~/
auto_compress = false
overwrite = true
;
Copy

Se você apagar ou renomear o arquivo, você não poderá mais chamar a UDF. Se você precisar atualizar seu arquivo, atualize-o enquanto nenhuma chamada para a UDF possa ser feita. Se o arquivo antigo ainda estiver no estágio, o comando PUT deverá incluir a cláusula OVERWRITE=TRUE.

Crie a UDF. O manipulador especifica o módulo e a função.

create or replace function dream(i int)
returns variant
language python
runtime_version = '3.8'
handler = 'sleepy.snore'
imports = ('@~/sleepy.py')
Copy

Chame a UDF:

select dream(3);

+----------+
| DREAM(3) |
|----------|
| [        |
|   "Zzz", |
|   "Zzz", |
|   "Zzz"  |
| ]        |
+----------+
Copy

Como especificar múltiplos arquivos de importação

Aqui está um exemplo de como especificar múltiplos arquivos de importação.

create or replace function multiple_import_files(s string)
returns string
language python
runtime_version=3.8
imports=('@python_udf_dep/bar/python_imports_a.zip', '@python_udf_dep/foo/python_imports_b.zip')
handler='compute'
as
$$
def compute(s):
  return s
$$;
Copy

Nota

Os nomes dos arquivos de importação especificados devem ser diferentes. Por exemplo, isso não vai funcionar: imports=('@python_udf_dep/bar/python_imports.zip', '@python_udf_dep/foo/python_imports.zip').

Concessão de privilégios sobre a função

Para que alguém com qualquer função que não seja a de proprietário chame a função, o proprietário deve conceder os privilégios adequados para a função.

As instruções GRANT para uma UDF de Python são essencialmente idênticas às instruções GRANT para outras UDFs, tais como UDFs de JavaScript.

Por exemplo:

GRANT USAGE ON FUNCTION my_python_udf(number, number) TO my_role;
Copy