Funções definidas pelo usuário em Python

Uma função definida pelo usuário (UDF) do Python permite implementar uma função escalar em Python e usá-la em uma consulta SQL. As UDFs do Python são semelhantes às UDFs do SQL e do JavaScript, mas com recursos adicionais. Com os UDFs do Python, é possível instalar bibliotecas de terceiros do índice de pacotes do Python (PyPI, na sigla em inglês) e acessar serviços externos usando uma conexão de recursos do Cloud.

Os UDFs do Python são criados e executados em recursos gerenciados pelo 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 do Python não têm suporte total nas visualizações INFORMATION_SCHEMA.
  • Não é possível criar ou atualizar um UDF Python usando a API Routine.
  • Não há suporte para o VPC Service Controls.
  • Não há suporte para chaves de criptografia gerenciadas pelo cliente (CMEK).
  • Os seguintes tipos de dados não são aceitos: JSON, RANGE, INTERVAL e GEOGRAPHY.

Papéis do IAM obrigatórios

Os papéis do IAM necessários são baseados em se você é um proprietário ou usuário de UDFs do Python. Um proprietário de UDF do Python normalmente cria ou atualiza uma UDF. Um usuário de UDFs do Python invoca uma UDF criada por outra pessoa.

Também são necessárias outras funções se você criar ou executar um UDF do Python que faz referência a uma conexão de recursos do Cloud.

Proprietários da UDF

Se você estiver criando ou atualizando uma UDF do 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)
  • bigquery.routines.create para criar um UDF do Python usando a instrução CREATE FUNCTION.
  • bigquery.routines.update para atualizar uma UDF do Python usando a instrução CREATE FUNCTION.
O conjunto de dados em que o UDF do Python é criado ou atualizado.
Usuário de jobs do BigQuery (roles/bigquery.jobUser)
  • bigquery.jobs.create para executar um job de consulta de instrução CREATE FUNCTION.
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á dando 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 da UDF

Se você estiver invocando um UDF do Python, os seguintes papéis predefinidos do IAM precisam 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 faz 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 o UDF do Python é armazenado.
Usuário de conexão do BigQuery (roles/bigquery.connectionUser) bigquery.connections.use para executar uma UDF do Python que faz referência a uma conexão de recursos do Cloud. A conexão de recursos do Cloud referenciada pela UDF em Python. Essa conexão é necessária apenas se o UDF referenciar uma conexão.

Para mais informações sobre papéis no BigQuery, consulte Papéis predefinidos do IAM.

Criar uma UDF Python permanente

Siga estas regras ao criar uma UDF Python:

  • O corpo da UDF do 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 do Python precisa incluir uma função do Python usada no argumento entry_point na lista de opções da UDF do Python.

  • Uma versão do ambiente de execução do Python precisa ser especificada na opção runtime_version. A única versão do ambiente de execução do Python com suporte é python-3.11. Para uma lista completa de opções disponíveis, consulte a lista de opções de função para a instrução CREATE FUNCTION.

Para criar uma UDF permanente do Python, use a instrução CREATE FUNCTION sem a palavra-chave TEMP ou TEMPORARY. Para excluir um UDF Python permanente, use a instrução DROP FUNCTION.

Quando você cria uma UDF do 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 após a execução da instrução CREATE FUNCTION pode esperar automaticamente a conclusão da imagem. Sem dependências externas, a imagem do contêiner geralmente é criada em menos de um minuto.

O exemplo a seguir cria uma UDF em Python permanente chamada multiplyInputs e chama a UDF de dentro de uma instrução SELECT:

  1. Acessar a página do BigQuery.

    Ir para o BigQuery

  2. 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 pelo ID do projeto e do conjunto de dados.

  3. Clique em  Run.

    Este exemplo produz a saída a seguir:

    +-----+-----+--------------+
    | x   | y   | product      |
    +-----+-----+--------------+
    | 1   | 5   |  5.0         |
    | 2   | 10  | 20.0         |
    | 3   | 15  | 45.0         |
    +-----+-----+--------------+
    

Criar uma UDF vetorializada em Python

É possível implementar a UDF do 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 lote, 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 para lote será determinado automaticamente.

Uma UDF vetorizada do Python 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 de UDF do Python definidos na instrução CREATE FUNCTION. Os nomes das colunas no argumento pandas.DataFrame têm os mesmos nomes 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 vetorizada em Python chamada multiplyInputs com dois parâmetros: x e y:

  1. Acessar a página do BigQuery.

    Ir para o BigQuery

  2. 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 pelo ID do projeto e do conjunto de dados.

    A chamada da UDF é igual ao exemplo anterior.

  3. Clique em  Run.

Tipos de dados de UDF em Python aceitos

A tabela a seguir define o mapeamento entre os tipos de dados do BigQuery, Python e Pandas:

Tipo de dados do BigQuery Tipo de dados integrado do Python usado por UDFs padrão Tipo de dados pandas usado por UDFs vetorizadas Tipo de dados PyArrow usado para ARRAY e STRUCT em UDFs vetorizadas
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: datetime.datetime (com fuso horário UTC definido)

Valor de retorno da função: datetime.datetime (com qualquer fuso horário definido)

Parâmetro da função: timestamp[us, tz=UTC][pyarrow]

Valor de retorno da função: timestamp[us, tz=*][pyarrow]\(any timezone\)

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 é pandas.ArrowDtype StructType

Versões do ambiente de execução com suporte

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. 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 daqueles 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, você precisa informar o nome dele e, opcionalmente, a versão usando os especificadores de versão de pacotes do 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 de 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 de rodas são aceitos.

O exemplo a seguir mostra como criar um UDF do Python que instala o pacote da biblioteca de cliente da API Cloud Translation usando a lista de opções CREATE OR REPLACE FUNCTION:

  1. Acessar a página do BigQuery.

    Ir para o BigQuery

  2. No editor de consultas, insira a seguinte instrução CREATE FUNCTION:

    CREATE FUNCTION `PROJECT_ID.DATASET_ID`.translate(src STRING)
    RETURNS STRING LANGUAGE python
    OPTIONS (entry_point='do_translate', runtime_version='python-3.11', packages=['google-cloud-translate>=3.11'])
    AS r"""
    from google.cloud import translate
    
    def do_translate(src):
      # See the example in following section for the detail guide and
      # the implementation
      return 
    """;

    Substitua PROJECT_ID.DATASET_ID pelo ID do projeto e do conjunto de dados.

  3. Clique em  Run.

Importar outros arquivos Python como bibliotecas

É possível estender as UDFs do Python usando a Lista de opções de função importando arquivos Python do Cloud Storage.

No código Python da UDF, é possível importar os arquivos Python do Cloud Storage como módulos usando a instrução de importação seguida pelo caminho para o 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 folder no nome do objeto (após o /) precisa ser um identificador válido do Python. 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 0 a 9, mas um número não pode aparecer como o primeiro caractere no identificador.

O exemplo a seguir mostra como criar uma UDF do Python que importe o pacote da biblioteca de cliente lib1.py de um bucket do Cloud Storage chamado my_bucket:

  1. Acessar a página do BigQuery.

    Ir para o BigQuery

  2. 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 pelo ID do projeto e do conjunto de dados.

  3. Clique em  Run.

Chamar Google Cloud ou serviços on-line no código Python

Um UDF do Python acessa um serviço Google Cloud ou 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 que é acessado e as APIs que são chamadas pelo código do Python.

Se você criar um UDF Python sem usar uma conexão de recurso do Cloud, a função será executada em um ambiente que bloqueia o acesso à rede. Se o UDF acessa serviços on-line, crie-o com uma conexão de recurso do Cloud. Caso contrário, o acesso do UDF à rede será bloqueado até que um tempo limite de conexão interno seja atingido.

O exemplo a seguir mostra como acessar o serviço do Cloud Translation em 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 em que você executa a tradução do Cloud chamada my_translate_project.

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ê vai precisar desse ID ao configurar as 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 à conta de serviço 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.

  1. Acessar a página IAM

    Acessar IAM

  2. Verifique se my_query_project está selecionado.

  3. Clique em Conceder acesso.

  4. No campo Novos principais, insira o ID da conta de serviço da conexão de recursos do Cloud que você copiou anteriormente.

  5. No campo Selecionar um papel, escolha Uso do serviço e, em seguida, selecione Consumidor do uso do serviço.

  6. Clique em Salvar.

  7. No seletor de projetos, escolha my_translate_project.

  8. Acessar a página IAM

    Acessar IAM

  9. Clique em Conceder acesso.

  10. No campo Novos principais, insira o ID da conta de serviço da conexão de recursos do Cloud que você copiou anteriormente.

  11. No campo Selecionar um papel, escolha Cloud Translation e, em seguida, selecione Usuário da API Cloud Translation.

  12. Clique em Salvar.

Criar uma UDF em Python que chame o serviço do Cloud Translation

Em my_query_project, crie um UDF Python que chame o serviço de tradução do Cloud usando sua conexão de recursos do Cloud.

  1. Acessar a página do BigQuery.

    Ir para o BigQuery

  2. Insira a instrução CREATE FUNCTION abaixo 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 dados
    • REGION.CONNECTION_ID: a região e o ID da conexão.
  3. Clique em  Run.

    A saída será semelhante a esta:

    +--------------------------+-------------------------------+
    | text                     | translated_text               |
    +--------------------------+-------------------------------+
    | Hello                    | Hola                          |
    | Good morning             | Buen dia                      |
    | Goodbye                  | Adios                         |
    +--------------------------+-------------------------------+
    

Locais suportados

Durante a visualização, as UDFs do Python são compatíveis com todos os locais multirregionais e regionais do BigQuery, exceto:

  • México
    • A região northamerica-south1 não é compatível.
  • Estocolmo
    • A região europe-north2 não é compatível.

Preços

As UDFs do Python são oferecidas sem custos adicionais.

Quando o faturamento está ativado, o seguinte se aplica:

  • As cobranças de UDFs em Python são faturadas usando a SKU dos Serviços do BigQuery.
  • As cobranças são proporcionais à quantidade de computação e memória consumidas quando o UDF do Python é invocado.
  • Os clientes de UDFs em Python também são cobrados pelo custo de criar ou refazer a imagem do contêiner de UDF. Essa cobrança é proporcional aos recursos usados para criar a imagem com o código e as dependências do cliente.
  • Se os UDFs do Python resultarem em saída externa ou de rede da Internet, você também vai encontrar uma cobrança de saída da Internet do nível Premium da rede do Cloud.