Funções definidas pelo usuário em Python
Com uma função definida pelo usuário (UDF) do Python, é possível implementar uma função escalar em Python e usá-la em uma consulta SQL. As UDFs em Python são semelhantes às UDFs em SQL e JavaScript, mas com recursos adicionais. As UDFs em Python permitem instalar bibliotecas de terceiros do índice de pacotes do Python (PyPI) e acessar serviços externos usando uma conexão de recursos do Cloud.
As UDFs em Python são criadas e executadas em recursos gerenciados do BigQuery.
Limitações
python-3.11
é o único ambiente de execução compatível.- Não é possível criar uma UDF temporária em Python.
- Não é possível usar uma UDF do Python com uma visualização materializada.
- Os resultados de uma consulta que chama uma UDF em Python não são armazenados em cache porque o valor de retorno de uma UDF em Python é sempre considerado não determinístico.
- As UDFs em Python não são totalmente compatíveis com as visualizações do
INFORMATION_SCHEMA
. - Não é possível criar ou atualizar uma UDF em Python usando a API Routine.
- Os controles de serviço da VPC não são compatíveis.
- As chaves de criptografia gerenciadas pelo cliente (CMEK, na sigla em inglês) não são compatíveis.
- Estes tipos de dados não são aceitos:
JSON
,RANGE
,INTERVAL
eGEOGRAPHY
. - Os contêineres que executam UDFs em Python podem ser configurados com até 2 vCPU e 8 Gi.
Papéis do IAM obrigatórios
Os papéis necessários do IAM dependem de você ser proprietário ou usuário de uma UDF do Python. Normalmente, o proprietário de uma UDF em Python cria ou atualiza uma UDF. Um usuário de UDF em Python invoca uma UDF criada por outra pessoa.
Outras funções também são necessárias se você criar ou executar uma UDF em Python que faça referência a uma conexão de recursos do Cloud.
Proprietários UDF
Se você estiver criando ou atualizando uma UDF em Python, os seguintes papéis predefinidos do IAM precisam ser concedidos no recurso apropriado:
Papel | Permissões necessárias | Recurso |
---|---|---|
Editor de dados do BigQuery (roles/bigquery.dataEditor )
|
|
O conjunto de dados em que a UDF Python é criada ou atualizada. |
Usuário de jobs do BigQuery (roles/bigquery.jobUser )
|
|
O projeto em que você está executando a instrução CREATE FUNCTION .
|
Administrador de conexão do BigQuery (roles/bigquery.connectionAdmin )
|
|
A conexão que você está acesso a um recurso externo. Essa conexão é necessária apenas se a UDF usar a cláusula WITH CONNECTION para acessar um serviço externo.
|
Usuários de UDF
Se você estiver invocando uma UDF em Python, os seguintes papéis predefinidos do IAM precisarão ser concedidos no recurso apropriado:
Papel | Permissões necessárias | Recurso |
---|---|---|
Usuário do BigQuery (roles/bigquery.user ) |
bigquery.jobs.create para executar um job de consulta que faça referência à
UDF. |
O projeto em que você está executando um job de consulta que invoca a UDF do Python. |
Visualizador de dados do BigQuery (roles/bigquery.dataViewer ) |
bigquery.routines.get para executar uma UDF criada por outra pessoa. |
O conjunto de dados em que a UDF Python está armazenada. |
Usuário de conexão do BigQuery (roles/bigquery.connectionUser ) |
bigquery.connections.use para executar uma UDF do Python que
referencia uma conexão de recursos do Cloud. |
A conexão de recurso do Cloud referenciada pela UDF em Python. Essa conexão só é necessária se a UDF fizer referência a uma conexão. |
Para mais informações sobre os papéis no BigQuery, consulte Papéis predefinidos do IAM.
Criar uma UDF Python permanente
Siga estas regras ao criar uma UDF em Python:
O corpo da UDF em Python precisa ser um literal de string entre aspas que representa o código Python. Para saber mais sobre literais de string entre aspas, consulte Formatos para literais entre aspas.
O corpo da UDF em Python precisa incluir uma função Python usada no argumento
entry_point
na lista de opções da UDF em Python.Uma versão do ambiente de execução do Python precisa ser especificada na opção
runtime_version
. A única versão compatível do ambiente de execução do Python épython-3.11
. Para uma lista completa das opções disponíveis, consulte a Lista de opções de função para a instruçãoCREATE FUNCTION
.
Para criar uma UDF permanente em Python, use a instrução CREATE FUNCTION
sem a palavra-chave TEMP
ou TEMPORARY
. Para excluir uma UDF Python permanente, use a instrução DROP FUNCTION
.
Quando você cria uma UDF em Python usando a instrução CREATE FUNCTION
,
o BigQuery cria ou atualiza uma imagem de contêiner com base em uma
imagem de base. O contêiner é criado na imagem de base usando seu código e as dependências de pacote especificadas. A criação do contêiner é um processo de longa duração. A primeira consulta depois de executar a instrução CREATE FUNCTION
pode
aguardar automaticamente a conclusão da imagem. Sem dependências externas, a imagem do contêiner geralmente é criada em menos de um minuto.
Exemplo
Para ver um exemplo de como criar uma UDF permanente em Python, escolha uma das seguintes opções:
Console
No exemplo a seguir, criamos uma UDF em Python permanente chamada multiplyInputs
e
a chamamos de dentro de uma instrução SELECT
:
Acessar a página do BigQuery.
No editor de consultas, insira a seguinte instrução
CREATE FUNCTION
:CREATE FUNCTION `PROJECT_ID.DATASET_ID`.multiplyInputs(x FLOAT64, y FLOAT64) RETURNS FLOAT64 LANGUAGE python OPTIONS(runtime_version="python-3.11", entry_point="multiply") AS r''' def multiply(x, y): return x * y '''; -- Call the Python UDF. WITH numbers AS (SELECT 1 AS x, 5 as y UNION ALL SELECT 2 AS x, 10 as y UNION ALL SELECT 3 as x, 15 as y) SELECT x, y, `PROJECT_ID.DATASET_ID`.multiplyInputs(x, y) AS product FROM numbers;
Substitua PROJECT_ID.DATASET_ID com o ID do projeto e do conjunto de dados.
Clique em
Executar.Este exemplo produz a saída a seguir:
+-----+-----+--------------+ | x | y | product | +-----+-----+--------------+ | 1 | 5 | 5.0 | | 2 | 10 | 20.0 | | 3 | 15 | 45.0 | +-----+-----+--------------+
BigQuery DataFrames
O exemplo a seguir usa DataFrames do BigQuery para transformar uma função personalizada em uma UDF do Python:
Criar uma UDF Python vetorizada
É possível implementar sua UDF em Python para processar um lote de linhas em vez de uma única linha usando a vetorização. A vetorização pode melhorar a performance da consulta.
Para controlar o comportamento de agrupamento em lotes, especifique o número máximo de linhas em cada lote usando a opção max_batching_rows
na lista de opções CREATE OR REPLACE FUNCTION
.
Se você especificar max_batching_rows
, o BigQuery vai determinar o número de linhas em um lote, até o limite de max_batching_rows
. Se max_batching_rows
não for especificado, o número de linhas a serem agrupadas será determinado automaticamente.
Uma UDF Python vetorizada tem um único argumento pandas.DataFrame
que precisa ser anotado. O argumento pandas.DataFrame
tem o mesmo número de colunas que os parâmetros da UDF do Python definidos na instrução CREATE FUNCTION
. Os nomes das colunas no argumento pandas.DataFrame
são os mesmos dos parâmetros da UDF.
Sua função precisa retornar um pandas.Series
ou um pandas.DataFrame
de coluna única com o mesmo número de linhas da entrada.
O exemplo a seguir cria uma UDF Python vetorizada chamada multiplyInputs
com dois parâmetros: x
e y
:
Acessar a página do BigQuery.
No editor de consultas, insira a seguinte instrução
CREATE FUNCTION
:CREATE FUNCTION `PROJECT_ID.DATASET_ID`.multiplyVectorized(x FLOAT64, y FLOAT64) RETURNS FLOAT64 LANGUAGE python OPTIONS(runtime_version="python-3.11", entry_point="vectorized_multiply") AS r''' import pandas as pd def vectorized_multiply(df: pd.DataFrame): return df['x'] * df['y'] ''';
Substitua PROJECT_ID.DATASET_ID com o ID do projeto e do conjunto de dados.
Chamar a UDF é o mesmo que no exemplo anterior.
Clique em
Executar.
Tipos de dados de UDF em Python compatíveis
A tabela a seguir define o mapeamento entre os tipos de dados do BigQuery, do Python e do Pandas:
Tipo de dados do BigQuery | Tipo de dados integrado do Python usado pela UDF padrão. | Tipo de dados do Pandas usado pela UDF vetorizada | Tipo de dados PyArrow usado para ARRAY e STRUCT em UDF vetorizada. |
---|---|---|---|
BOOL |
bool |
BooleanDtype |
DataType(bool) |
INT64 |
int |
Int64Dtype |
DataType(int64) |
FLOAT64 |
float |
FloatDtype |
DataType(double) |
STRING |
str |
StringDtype |
DataType(string) |
BYTES |
bytes |
binary[pyarrow] |
DataType(binary) |
TIMESTAMP |
Parâmetro de função: Valor de retorno da função: |
Parâmetro da função: Valor de retorno da função: |
TimestampType(timestamp[us]) , com fuso horário |
DATE |
datetime.date |
date32[pyarrow] |
DataType(date32[day]) |
TIME |
datetime.time |
time64[pyarrow] |
Time64Type(time64[us]) |
DATETIME |
datetime.datetime (sem fuso horário) |
timestamp[us][pyarrow] |
TimestampType(timestamp[us]) , sem fuso horário |
ARRAY |
list |
list<...>[pyarrow] , em que o tipo de dados do elemento é um pandas.ArrowDtype |
ListType |
STRUCT |
dict |
struct<...>[pyarrow] , em que o tipo de dados do campo é um pandas.ArrowDtype |
StructType |
Versões de ambiente de execução compatíveis
As UDFs do BigQuery em Python são compatíveis com o ambiente de execução python-3.11
. Essa versão do Python inclui alguns pacotes pré-instalados adicionais. Para bibliotecas do sistema, verifique a imagem de base do ambiente de execução.
Versão do ambiente de execução | Versão do Python | Inclui | Imagem de base do ambiente de execução |
---|---|---|---|
python-3.11 | Python 3.11 | numpy 1.26.3 pyarrow 14.0.2 pandas 2.1.4 python-dateutil 2.8.2 |
google-22-full/python311 |
Usar pacotes de terceiros
É possível usar a lista de opções CREATE FUNCTION
para usar módulos diferentes dos fornecidos pela biblioteca padrão do Python
e pacotes pré-instalados. É possível instalar pacotes do índice de pacotes do Python (PyPI) ou importar arquivos do Python do Cloud Storage.
Instalar um pacote do índice de pacotes do Python
Ao instalar um pacote, é preciso informar o nome dele e, opcionalmente, a versão usando especificadores de versão de pacote Python.
Se o pacote estiver no ambiente de execução, ele será usado, a menos que uma versão específica seja especificada na lista de opções CREATE FUNCTION
. Se uma versão do pacote
não for especificada e o pacote não estiver no ambiente de execução, a versão mais recente disponível
será usada. Somente pacotes com o formato binário wheels
são compatíveis.
O exemplo a seguir mostra como criar uma UDF do Python que instala o
pacote scipy
usando a lista de opções CREATE OR REPLACE FUNCTION
:
Acessar a página do BigQuery.
No editor de consultas, insira a seguinte instrução
CREATE FUNCTION
:CREATE FUNCTION `PROJECT_ID.DATASET_ID`.area(radius FLOAT64) RETURNS FLOAT64 LANGUAGE python OPTIONS (entry_point='area_handler', runtime_version='python-3.11', packages=['scipy==1.15.3']) AS r""" import scipy def area_handler(radius): return scipy.constants.pi*radius*radius """; SELECT `PROJECT_ID.DATASET_ID`.area(4.5);
Substitua PROJECT_ID.DATASET_ID com o ID do projeto e do conjunto de dados.
Clique em
Executar.
Importar outros arquivos Python como bibliotecas
É possível estender suas UDFs do Python usando a lista de opções de função ao importar arquivos Python do Cloud Storage.
No código Python da sua UDF, é possível importar os arquivos do Cloud Storage como módulos usando a instrução "import" seguida pelo caminho do objeto do Cloud Storage. Por exemplo, se você estiver importando
gs://BUCKET_NAME/path/to/lib1.py
, a instrução de importação será
import path.to.lib1
.
O nome do arquivo Python precisa ser um identificador do Python. Cada nome de folder
no nome do objeto (após o /
) precisa ser um identificador Python válido. No intervalo ASCII (U+0001..U+007F), os seguintes caracteres podem ser usados em identificadores:
- Letras maiúsculas e minúsculas de A a Z.
- Sublinhados.
- Os dígitos de zero a nove, mas um número não pode aparecer como o primeiro caractere no identificador.
O exemplo a seguir mostra como criar uma UDF em Python que importa o pacote da biblioteca de cliente
lib1.py
de um bucket do Cloud Storage chamado
my_bucket
:
Acessar a página do BigQuery.
No editor de consultas, insira a seguinte instrução
CREATE FUNCTION
:CREATE FUNCTION `PROJECT_ID.DATASET_ID`.myFunc(a FLOAT64, b STRING) RETURNS STRING LANGUAGE python OPTIONS ( entry_point='compute', runtime_version='python-3.11', library=['gs://my_bucket/path/to/lib1.py']) AS r""" import path.to.lib1 as lib1 def compute(a, b): # doInterestingStuff is a function defined in # gs://my_bucket/path/to/lib1.py return lib1.doInterestingStuff(a, b); """;
Substitua PROJECT_ID.DATASET_ID com o ID do projeto e do conjunto de dados.
Clique em
Executar.
Configurar limites de contêiner para UDFs do Python
Use a lista de opções CREATE FUNCTION
para especificar limites de CPU e memória para contêineres que executam UDFs em Python.
Por padrão, a memória alocada para cada instância de contêiner é de 512 MiB, e a CPU alocada é de 0,33 vCPU.
O exemplo a seguir cria uma UDF do Python
usando a lista de opções CREATE FUNCTION
para especificar limites de contêiner:
Acessar a página do BigQuery.
No editor de consultas, insira a seguinte instrução
CREATE FUNCTION
:CREATE FUNCTION `PROJECT_ID.DATASET_ID`.resizeImage(image BYTES) RETURNS BYTES LANGUAGE python OPTIONS (entry_point='resize_image', runtime_version='python-3.11', packages=['Pillow==11.2.1'], container_memory='2Gi', container_cpu=1) AS r""" import io from PIL import Image def resize_image(image_bytes): img = Image.open(io.BytesIO(image_bytes)) resized_img = img.resize((256, 256), Image.Resampling.LANCZOS) output_stream = io.BytesIO() resized_img.convert('RGB').save(output_stream, format='JPEG') return output_stream.getvalue() """;
Substitua PROJECT_ID.DATASET_ID com o ID do projeto e do conjunto de dados.
Clique em
Executar.
Valores de CPU aceitos
As UDFs em Python aceitam valores fracionários de CPU entre 0.33
e 1.0
e valores não fracionários de CPU de 1
e 2
. Os valores de entrada fracionários são arredondados para duas casas decimais antes de serem aplicados ao contêiner.
Valores de memória compatíveis
Os contêineres de UDF do Python aceitam valores de memória no seguinte formato: <integer_number><unit>
. A unidade precisa ser um destes valores: Mi
, M
, Gi
e G
. A quantidade mínima de memória que pode ser configurada é de 256 mebibytes (256 Mi).
A quantidade máxima de memória que você pode configurar é de 8 gibibytes (8 Gi).
Com base no valor de memória escolhido, especifique também a quantidade mínima de CPU. A tabela a seguir mostra os valores mínimos de CPU para cada valor de memória:
Memória | CPU mínima |
---|---|
512 MiB or less |
0.33 |
More than 512 MiB |
0.5 |
More than 1 GiB |
1 |
More than 4 GiB |
2 |
Chamar Google Cloud ou serviços on-line em código Python
Uma UDF em Python acessa um serviço Google Cloud ou um serviço externo usando a conta de serviço da Conexão de recursos do Cloud. A conta de serviço da conexão precisa receber permissões para acessar o serviço. As permissões necessárias variam de acordo com o serviço acessado e as APIs chamadas no código Python.
Se você criar uma UDF em Python sem usar uma conexão de recurso do Cloud, a função será executada em um ambiente que bloqueia o acesso à rede. Se a UDF acessar serviços on-line, crie-a com uma conexão de recursos do Cloud. Caso contrário, a UDF não poderá acessar a rede até que um tempo limite de conexão interna seja atingido.
O exemplo a seguir mostra como acessar o serviço Cloud Translation
de uma UDF do Python. Este exemplo tem dois projetos: um chamado my_query_project
, em que você cria a UDF e a conexão de recursos do Cloud, e outro chamado my_translate_project
, em que você executa o Cloud Translation.
Criar uma conexão de recursos do Cloud
Primeiro, crie uma conexão de recursos do Cloud em my_query_project
. Para criar
a conexão de recursos do Cloud, siga as etapas na página Criar uma conexão de recursos
do Cloud.
Depois de criar a conexão, abra-a e, no painel Informações da conexão, copie o ID da conta de serviço. Você precisa desse ID ao configurar permissões para a conexão. Quando você cria um recurso de conexão, o BigQuery cria uma conta de serviço do sistema exclusiva e a associa à conexão.
Conceder acesso à conta de serviço da conexão
Para conceder à conta de serviço de conexão de recursos do Cloud acesso aos seus projetos, conceda a ela o papel de consumidor de uso do serviço (roles/serviceusage.serviceUsageConsumer
) em my_query_project
e o papel de usuário da API Cloud Translation (roles/cloudtranslate.user
) em my_translate_project
.
Acessar a página IAM
Verifique se
my_query_project
está selecionado.Clique em
Conceder acesso.No campo Novos principais, insira o ID da conta de serviço da conexão de recursos do Cloud que você copiou anteriormente.
No campo Selecionar um papel, escolha Service Usage e selecione Consumidor do Service Usage.
Clique em Salvar.
No seletor de projetos, escolha
my_translate_project
.Acessar a página IAM
Clique em
Conceder acesso.No campo Novos principais, insira o ID da conta de serviço da conexão de recursos do Cloud que você copiou anteriormente.
No campo Selecionar um papel, escolha Cloud Translation e, em seguida, selecione Usuário da API Cloud Translation.
Clique em Salvar.
Criar uma UDF em Python que chama o serviço do Cloud Translation
Em my_query_project
, crie uma UDF em Python que chame o serviço do Cloud Translation
usando sua conexão de recurso do Cloud.
Acessar a página do BigQuery.
Insira a seguinte instrução
CREATE FUNCTION
no editor de consultas:CREATE FUNCTION `PROJECT_ID.DATASET_ID`.translate_to_es(x STRING) RETURNS STRING LANGUAGE python WITH CONNECTION `PROJECT_ID.REGION.CONNECTION_ID` OPTIONS (entry_point='do_translate', runtime_version='python-3.11', packages=['google-cloud-translate>=3.11', 'google-api-core']) AS r""" from google.api_core.retry import Retry from google.cloud import translate project = "my_translate_project" translate_client = translate.TranslationServiceClient() def do_translate(x : str) -> str: response = translate_client.translate_text( request={ "parent": f"projects/{project}/locations/us-central1", "contents": [x], "target_language_code": "es", "mime_type": "text/plain", }, retry=Retry(), ) return response.translations[0].translated_text """; -- Call the UDF. WITH text_table AS (SELECT "Hello" AS text UNION ALL SELECT "Good morning" AS text UNION ALL SELECT "Goodbye" AS text) SELECT text, `PROJECT_ID.DATASET_ID`.translate_to_es(text) AS translated_text FROM text_table;
Substitua:
PROJECT_ID.DATASET_ID
: o ID do projeto e do conjunto de dadosREGION.CONNECTION_ID
: a região e o ID da sua conexão
Clique em
Executar.A saída será semelhante a esta:
+--------------------------+-------------------------------+ | text | translated_text | +--------------------------+-------------------------------+ | Hello | Hola | | Good morning | Buen dia | | Goodbye | Adios | +--------------------------+-------------------------------+
Locais suportados
As UDFs em Python são compatíveis com todos os locais multirregionais e regionais do BigQuery.
Preços
As UDFs em Python são oferecidas sem custos extras.
Quando o faturamento está ativado, o seguinte se aplica:
- As cobranças de UDFs em Python são feitas usando a SKU de serviços do BigQuery.
- As cobranças são proporcionais à quantidade de computação e memória consumidas quando a UDF do Python é invocada.
- Os clientes de UDFs em Python também são cobrados pelo custo de criação ou recriação da imagem do contêiner da UDF. Essa cobrança é proporcional aos recursos usados para criar a imagem com o código e as dependências do cliente.
- Se as UDFs do Python resultarem em saída de rede externa ou da Internet, você também vai receber uma cobrança de saída da Internet do nível Premium do Cloud Networking.