Trabalhar com 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. Com as UDFs em Python, é possível instalar bibliotecas de terceiros no índice de pacotes do Python (PyPI) e acessar serviços externos usando uma conexão de recurso 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.
  • Redes VPC não são compatíveis.
  • Assured Workloads não é compatível.
  • Estes tipos de dados não são aceitos: JSON, RANGE, INTERVAL e GEOGRAPHY.
  • Os contêineres que executam UDFs do Python só podem ser configurados com até 4 vCPU e 16 GiB.
  • As chaves de criptografia gerenciadas pelo cliente (CMEK) não são compatíveis.

Funções exigidas

Os papéis necessários do IAM dependem de você ser proprietário ou usuário de uma UDF do Python.

Proprietários UDF

Normalmente, o proprietário de uma UDF em Python cria ou atualiza uma UDF. Outras funções também são necessárias se você criar uma UDF em Python que faça referência a uma conexão a recursos do Cloud. Essa conexão só é necessária se a UDF usar a cláusula WITH CONNECTION para acessar um serviço externo.

Para receber as permissões necessárias para criar ou atualizar uma UDF em Python, peça ao administrador que conceda a você os seguintes papéis do IAM:

Para mais informações sobre a concessão de papéis, consulte Gerenciar o acesso a projetos, pastas e organizações.

Esses papéis predefinidos contêm as permissões necessárias para criar ou atualizar uma UDF em Python. Para acessar as permissões exatas necessárias, expanda a seção Permissões necessárias:

Permissões necessárias

As seguintes permissões são necessárias para criar ou atualizar uma UDF em Python:

  • Crie uma UDF do Python usando a instrução CREATE FUNCTION: bigquery.routines.create no conjunto de dados
  • Atualize uma UDF do Python usando a instrução CREATE FUNCTION: bigquery.routines.update no conjunto de dados
  • Execute um job de consulta de instrução CREATE FUNCTION: bigquery.jobs.create no projeto
  • Crie uma conexão de recursos do Cloud: bigquery.connections.create no projeto
  • Use uma conexão na instrução CREATE FUNCTION: bigquery.connections.delegate na conexão

Essas permissões também podem ser concedidas com funções personalizadas ou outros papéis predefinidos.

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

Usuários de 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ê invocar uma UDF do Python que faz referência a uma conexão de recurso do Cloud.

Para receber as permissões necessárias para invocar uma UDF em Python criada por outra pessoa, peça ao administrador para conceder a você os seguintes papéis do IAM:

Para mais informações sobre a concessão de papéis, consulte Gerenciar o acesso a projetos, pastas e organizações.

Esses papéis predefinidos contêm as permissões necessárias para invocar uma UDF em Python criada por outra pessoa. Para acessar as permissões exatas necessárias, expanda a seção Permissões necessárias:

Permissões necessárias

As seguintes permissões são necessárias para invocar uma UDF em Python criada por outra pessoa:

  • Para executar um job de consulta que faz referência a uma UDF em Python: bigquery.jobs.create no projeto
  • Para invocar uma UDF em Python criada por outra pessoa: bigquery.routines.get no conjunto de dados
  • Para executar uma UDF em Python que faz referência a uma conexão a recursos do Cloud: bigquery.connections.use na conexão

Essas permissões também podem ser concedidas com funções personalizadas ou outros papéis predefinidos.

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

Chamar uma UDF em Python

Se você tiver permissão para invocar uma UDF em Python, poderá chamá-la como qualquer outra função. Para usar uma função definida em um projeto diferente, use o nome totalmente qualificado dela. Por exemplo, para chamar a UDF do Python cw_xml_extract definida como uma UDF da comunidade bigquery-utils, siga estas etapas:

Console

  1. Acessar a página do BigQuery.

    Acessar o BigQuery

  2. No editor de consultas, insira o seguinte exemplo:

    SELECT
      `bqutil`.`fn`.`cw_xml_extract`(xml, '//title/text()') AS `title`
    FROM UNNEST([
      STRUCT('''<book id="1">
        <title>The Great Gatsby</title>
        <author>F. Scott Fitzgerald</author>
      </book>''' AS xml),
      STRUCT('''<book id="2">
        <title>1984</title>
        <author>George Orwell</author>
      </book>''' AS xml),
      STRUCT('''<book id="3">
        <title>Brave New World</title>
        <author>Aldous Huxley</author>
      </book>''' AS xml)
    ])
    
  3. Clique em  Executar.

    Este exemplo produz a saída a seguir:

    +--------------------------+
    | title                    |
    +--------------------------+
    | The Great Gatsby         |
    | 1984                     |
    | Brave New World          |
    +--------------------------+
    

BigQuery DataFrames

O exemplo a seguir usa os métodos BigQuery DataFrames sql_scalar, read_gbq_function, e apply para chamar uma UDF em Python:

import textwrap
from typing import Tuple

import bigframes.pandas as bpd
import pandas as pd
import pyarrow as pa


# Using partial ordering mode enables more efficient query optimizations.
bpd.options.bigquery.ordering_mode = "partial"


def call_python_udf(
    project_id: str, location: str,
) -> Tuple[pd.Series, bpd.Series]:
    # Set the billing project to use for queries. This step is optional, as the
    # project can be inferred from your environment in many cases.
    bpd.options.bigquery.project = project_id  # "your-project-id"

    # Since this example works with local data, set a processing location.
    bpd.options.bigquery.location = location  # "US"

    # Create a sample series.
    xml_series = pd.Series(
        [
            textwrap.dedent(
                """
                <book id="1">
                    <title>The Great Gatsby</title>
                    <author>F. Scott Fitzgerald</author>
                </book>
                """
            ),
            textwrap.dedent(
                """
                <book id="2">
                    <title>1984</title>
                    <author>George Orwell</author>
                </book>
                """
            ),
            textwrap.dedent(
                """
                <book id="3">
                    <title>Brave New World</title>
                    <author>Aldous Huxley</author>
                </book>
                """
            ),
        ],
        dtype=pd.ArrowDtype(pa.string()),
    )
    df = pd.DataFrame({"xml": xml_series})

    # Use the BigQuery Accessor, which is automatically registered on pandas
    # DataFrames when you import bigframes.  This example uses a function that
    # has been deployed to bigquery-utils for demonstration purposes. To use in
    # production, deploy the function at
    # https://github.com/GoogleCloudPlatform/bigquery-utils/blob/master/udfs/community/cw_xml_extract.sqlx
    # to your own project.
    titles_pandas = df.bigquery.sql_scalar(
        "`bqutil`.`fn`.cw_xml_extract({xml}, '//title/text()')",
    )

    # Alternatively, call read_gbq_function to get a pointer to the function
    # that can be applied on BigQuery DataFrames objects.
    cw_xml_extract = bpd.read_gbq_function("bqutil.fn.cw_xml_extract")
    xml_bigframes = bpd.read_pandas(xml_series)

    xpath_query = "//title/text()"
    titles_bigframes = xml_bigframes.apply(cw_xml_extract, args=(xpath_query,))
    return titles_pandas, titles_bigframes

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 da instrução CREATE 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 do 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

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

  1. Acessar a página do BigQuery.

    Acessar 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 com o ID do projeto e do conjunto de dados.

  3. 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 o BigQuery DataFrames para transformar uma função personalizada em uma UDF do Python:

import bigframes.pandas as bpd

# Set BigQuery DataFrames options
bpd.options.bigquery.project = your_gcp_project_id
bpd.options.bigquery.location = "US"

# BigQuery DataFrames gives you the ability to turn your custom functions
# into a BigQuery Python UDF. One can find more details about the usage and
# the requirements via `help` command.
help(bpd.udf)

# Read a table and inspect the column of interest.
df = bpd.read_gbq("bigquery-public-data.ml_datasets.penguins")
df["body_mass_g"].peek(10)

# Define a custom function, and specify the intent to turn it into a
# BigQuery Python UDF. Let's try a `pandas`-like use case in which we want
# to apply a user defined function to every value in a `Series`, more
# specifically bucketize the `body_mass_g` value of the penguins, which is a
# real number, into a category, which is a string.
@bpd.udf(
    dataset=your_bq_dataset_id,
    name=your_bq_routine_id,
)
def get_bucket(num: float) -> str:
    if not num:
        return "NA"
    boundary = 4000
    return "at_or_above_4000" if num >= boundary else "below_4000"

# Then we can apply the udf on the `Series` of interest via
# `apply` API and store the result in a new column in the DataFrame.
df = df.assign(body_mass_bucket=df["body_mass_g"].apply(get_bucket))

# This will add a new column `body_mass_bucket` in the DataFrame. You can
# preview the original value and the bucketized value side by side.
df[["body_mass_g", "body_mass_bucket"]].peek(10)

# The above operation was possible by doing all the computation on the
# cloud through an underlying BigQuery Python UDF that was created to
# support the user's operations in the Python code.

# The BigQuery Python UDF created to support the BigQuery DataFrames
# udf can be located via a property `bigframes_bigquery_function`
# set in the udf object.
print(f"Created BQ Python UDF: {get_bucket.bigframes_bigquery_function}")

# If you have already defined a custom function in BigQuery, either via the
# BigQuery Google Cloud Console or with the `udf` decorator,
# or otherwise, you may use it with BigQuery DataFrames with the
# `read_gbq_function` method. More details are available via the `help`
# command.
help(bpd.read_gbq_function)

existing_get_bucket_bq_udf = get_bucket.bigframes_bigquery_function

# Here is an example of using `read_gbq_function` to load an existing
# BigQuery Python UDF.
df = bpd.read_gbq("bigquery-public-data.ml_datasets.penguins")
get_bucket_function = bpd.read_gbq_function(existing_get_bucket_bq_udf)

df = df.assign(body_mass_bucket=df["body_mass_g"].apply(get_bucket_function))
df.peek(10)

# Let's continue trying other potential use cases of udf. Let's say we
# consider the `species`, `island` and `sex` of the penguins sensitive
# information and want to redact that by replacing with their hash code
# instead. Let's define another scalar custom function and decorate it
# as a udf. The custom function in this example has external package
# dependency, which can be specified via `packages` parameter.
@bpd.udf(
    dataset=your_bq_dataset_id,
    name=your_bq_routine_id,
    packages=["cryptography"],
)
def get_hash(input: str) -> str:
    from cryptography.fernet import Fernet

    # handle missing value
    if input is None:
        input = ""

    key = Fernet.generate_key()
    f = Fernet(key)
    return f.encrypt(input.encode()).decode()

# We can use this udf in another `pandas`-like API `map` that
# can be applied on a DataFrame
df_redacted = df[["species", "island", "sex"]].map(get_hash)
df_redacted.peek(10)

# If the BigQuery routine is no longer needed, we can clean it up
# to free up any cloud quota
session = bpd.get_global_session()
session.bqclient.delete_routine(f"{your_bq_dataset_id}.{your_bq_routine_id}")

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 o desempenho da consulta. É possível criar uma UDF vetorizada usando Pandas ou Apache Arrow.

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.

Usar o Pandas

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 em 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:

  1. Acessar a página do BigQuery.

    Acessar 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 com o ID do projeto e do conjunto de dados.

    Chamar a UDF é o mesmo que no exemplo anterior.

  3. Clique em  Executar.

Usar o Apache Arrow

O exemplo a seguir usa a interface RecordBatch do Apache Arrow. Ao usar a interface RecordBatch, a função transmite um lote de linhas de colunas de igual comprimento ao ponto de entrada. O exemplo a seguir usa o Apache Arrow para criar uma UDF Python vetorizada chamada multiplyVectorizedArrow.

  1. Acessar a página do BigQuery.

    Acessar o BigQuery

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

    CREATE FUNCTION `PROJECT_ID.DATASET_ID`.multiplyVectorizedArrow(x FLOAT64, y FLOAT64)
    RETURNS FLOAT64
    LANGUAGE python
    OPTIONS(
      runtime_version="python-3.11",
      entry_point="vectorized_multiply_arrow"
    )
    AS r'''
    import pyarrow as pa
    import pyarrow.compute as pc
    
    def vectorized_multiply_arrow(batch: pa.RecordBatch):
        # Access columns directly from the Arrow RecordBatch
        x = batch.column('x')
        y = batch.column('y')
    
        # Use pyarrow.compute for vectorized operations
        return pc.multiply(x, y)
    ''';

    Substitua PROJECT_ID.DATASET_ID com o ID do projeto e do conjunto de dados.

    Chamar a UDF é o mesmo que nos exemplos anteriores.

  3. 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: datetime.datetime (com o 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 é 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
python-3.11 Python 3.11 numpy 1.26.3
pyarrow 14.0.2
pandas 2.1.4
python-dateutil 2.8.2
absl-py 2.0.0
pytz 2023.3.post1
tzdata 2023.4
six 1.16.0
grpcio 1.76.0
grpcio-protobuf 6.33.5tools 1.76.0
typing-extensions 4.15.0

Usar pacotes de terceiros

Use 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, é necessário fornecer o nome dele e, opcionalmente, a versão usando especificadores de versão de pacote 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 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:

  1. Acessar a página do BigQuery.

    Acessar o BigQuery

  2. 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.

  3. Clique em  Executar.

Importar outros arquivos Python como bibliotecas

É possível estender as UDFs do Python usando a lista de opções de função (em inglês) 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:

  1. Acessar a página do BigQuery.

    Acessar 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 com o ID do projeto e do conjunto de dados.

  3. Clique em  Executar.

Configurar limites de contêiner para UDFs do Python

Use a lista de opções CREATE FUNCTION para especificar limites de simultaneidade de solicitações de CPU, memória e contêineres que executam UDFs em Python.

Por padrão, os contêineres recebem os seguintes recursos:

  • A memória alocada é 512Mi.
  • A CPU alocada é de 1.0 vCPU.
  • O limite de simultaneidade de solicitações de contêiner é 80.

O exemplo a seguir cria uma UDF do Python usando a lista de opções CREATE FUNCTION para especificar limites de contêiner:

  1. Acessar a página do BigQuery.

    Acessar o BigQuery

  2. 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='CONTAINER_MEMORY', container_cpu=CONTAINER_CPU,
    container_request_concurrency=CONTAINER_REQUEST_CONCURRENCY)
    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: o ID do projeto e do conjunto de dados.
    • CONTAINER_MEMORY: o valor da memória no formato <integer_number><unit>. A unidade precisa ser um destes valores: Mi (MiB), M (MB), Gi (GiB) ou G (GB). Exemplo: 2Gi.
    • CONTAINER_CPU: o valor da CPU. As UDFs do Python aceitam valores fracionários de CPU entre 0.33 e 1.0 e valores não fracionários de CPU de 1, 2 e 4.
    • CONTAINER_REQUEST_CONCURRENCY: o número máximo de solicitações simultâneas por instância de contêiner de UDF do Python. O valor precisa ser um número inteiro de 1 a 1000.
  3. Clique em  Executar.

Valores de CPU aceitos

As UDFs do Python são compatíveis com valores fracionários de CPU entre 0.33 e 1.0 e valores não fracionários de CPU de 1, 2 e 4. Os contêineres que executam UDFs do Python podem ser configurados com até 4 vCPU. O valor padrão é 1.0. Valores de entrada fracionários são arredondados para duas casas decimais antes de serem aplicados ao contêiner.

Valores de memória aceitos

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 é 256Mi. A quantidade máxima de memória que pode ser configurada é 16Gi.

Com base no valor de memória escolhido, você também precisa especificar uma quantidade adequada de CPU. A tabela a seguir mostra os valores mínimos e máximos de CPU para cada valor de memória:

Memória CPU mínima CPU máxima
256Mi a 512Mi 0.33 2
Maior que 512Mi e menor ou igual a 1Gi 0.5 2
Maior que 1Gi e menor que 2Gi 1 2
2Gi a 4Gi 1 4
Maior que 4Gi e até 8Gi 2 4
Maior que 8Gi e até 16Gi 4 4

Como alternativa, se você já determinou a quantidade de CPU que está alocando, use a tabela a seguir para determinar o intervalo de memória adequado:

CPU Memória mínima Máximo de memória
Menos de 0.5 256Mi 512Mi
0.5 para menos de 1 256Mi 1Gi
1 256Mi 4Gi
2 256Mi 8Gi
4 2Gi 16Gi

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 a 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 a recursos 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 a recursos do Cloud, e outro em que você executa o Cloud Translation, chamado my_translate_project.

Criar uma conexão de recursos do Cloud

Primeiro, crie uma conexão a recursos do Cloud em my_query_project. Para criar a conexão a recursos do Cloud, siga estas etapas.

Selecione uma das seguintes opções:

Console

  1. Acessar a página do BigQuery.

    Acessar o BigQuery

  2. No painel à esquerda, clique em Explorer:

    Botão destacado para o painel &quot;Explorer&quot;.

    Se o painel esquerdo não aparecer, clique em Expandir painel esquerdo para abrir.

  3. No painel Explorer, expanda o nome do projeto e clique em Conexões.

  4. Na página Conexões, clique em Criar conexão.

  5. Em Tipo de conexão, escolha Modelos remotos da Vertex AI, funções remotas, BigLake e Spanner (recurso do Cloud).

  6. No campo ID da conexão, insira um nome para a conexão.

  7. Em Tipo de local, selecione um local para sua conexão. A conexão precisa estar no mesmo local que seus outros recursos, como conjuntos de dados.

  8. Clique em Criar conexão.

  9. Clique em Ir para conexão.

  10. No painel Informações da conexão, copie o ID da conta de serviço para usar em uma etapa posterior.

SQL

Use a instrução CREATE CONNECTION:

  1. No console do Google Cloud , acesse a página BigQuery.

    Acessar o BigQuery

  2. No editor de consultas, digite a seguinte instrução:

    CREATE CONNECTION [IF NOT EXISTS] `CONNECTION_NAME`
    OPTIONS (
      connection_type = "CLOUD_RESOURCE",
      friendly_name = "FRIENDLY_NAME",
      description = "DESCRIPTION"
      );

    Substitua:

    • CONNECTION_NAME: o nome da conexão no formato PROJECT_ID.LOCATION.CONNECTION_ID, LOCATION.CONNECTION_ID ou CONNECTION_ID. Se o projeto ou local for omitido, eles serão inferidos do projeto e do local em que a instrução é executada.
    • FRIENDLY_NAME (opcional): um nome descritivo para a conexão.
    • DESCRIPTION (opcional): uma descrição da conexão.

  3. Clique em Executar.

Para mais informações sobre como executar consultas, acesse Executar uma consulta interativa.

bq

  1. Em um ambiente de linha de comando, crie uma conexão:

    bq mk --connection --location=REGION --project_id=PROJECT_ID \
        --connection_type=CLOUD_RESOURCE CONNECTION_ID

    O parâmetro --project_id substitui o projeto padrão.

    Substitua:

    • REGION: sua região de conexão
    • PROJECT_ID: o ID do projeto do Google Cloud
    • CONNECTION_ID: um ID para sua 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.

    Solução de problemas: se você receber o seguinte erro de conexão, atualize o SDK Google Cloud:

    Flags parsing error: flag --connection_type=CLOUD_RESOURCE: value should be one of...
    
  2. Recupere e copie o ID da conta de serviço para uso em uma etapa posterior:

    bq show --connection PROJECT_ID.REGION.CONNECTION_ID

    O resultado será o seguinte:

    name                          properties
    1234.REGION.CONNECTION_ID     {"serviceAccountId": "connection-1234-9u56h9@gcp-sa-bigquery-condel.iam.gserviceaccount.com"}
    

Python

Antes de testar esta amostra, siga as instruções de configuração do Python no Guia de início rápido do BigQuery: como usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API BigQuery em Python.

Para autenticar no BigQuery, configure o Application Default Credentials. Para mais informações, acesse Configurar a autenticação para bibliotecas de cliente.

import google.api_core.exceptions
from google.cloud import bigquery_connection_v1

client = bigquery_connection_v1.ConnectionServiceClient()


def create_connection(
    project_id: str,
    location: str,
    connection_id: str,
):
    """Creates a BigQuery connection to a Cloud Resource.

    Cloud Resource connection creates a service account which can then be
    granted access to other Google Cloud resources for federated queries.

    Args:
        project_id: The Google Cloud project ID.
        location: The location of the connection (for example, "us-central1").
        connection_id: The ID of the connection to create.
    """

    parent = client.common_location_path(project_id, location)

    connection = bigquery_connection_v1.Connection(
        friendly_name="Example Connection",
        description="A sample connection for a Cloud Resource.",
        cloud_resource=bigquery_connection_v1.CloudResourceProperties(),
    )

    try:
        created_connection = client.create_connection(
            parent=parent, connection_id=connection_id, connection=connection
        )
        print(f"Successfully created connection: {created_connection.name}")
        print(f"Friendly name: {created_connection.friendly_name}")
        print(
            f"Service Account: {created_connection.cloud_resource.service_account_id}"
        )

    except google.api_core.exceptions.AlreadyExists:
        print(f"Connection with ID '{connection_id}' already exists.")
        print("Please use a different connection ID.")
    except Exception as e:
        print(f"An unexpected error occurred while creating the connection: {e}")

Node.js

Antes de testar esta amostra, siga as instruções de configuração do Node.js no Guia de início rápido do BigQuery: como usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API BigQuery em Node.js.

Para autenticar no BigQuery, configure o Application Default Credentials. Para mais informações, acesse Configurar a autenticação para bibliotecas de cliente.

const {ConnectionServiceClient} =
  require('@google-cloud/bigquery-connection').v1;
const {status} = require('@grpc/grpc-js');

const client = new ConnectionServiceClient();

/**
 * Creates a new BigQuery connection to a Cloud Resource.
 *
 * A Cloud Resource connection creates a service account that can be granted access
 * to other Google Cloud resources.
 *
 * @param {string} projectId The Google Cloud project ID. for example, 'example-project-id'
 * @param {string} location The location of the project to create the connection in. for example, 'us-central1'
 * @param {string} connectionId The ID of the connection to create. for example, 'example-connection-id'
 */
async function createConnection(projectId, location, connectionId) {
  const parent = client.locationPath(projectId, location);

  const connection = {
    friendlyName: 'Example Connection',
    description: 'A sample connection for a Cloud Resource',
    // The service account for this cloudResource will be created by the API.
    // Its ID will be available in the response.
    cloudResource: {},
  };

  const request = {
    parent,
    connectionId,
    connection,
  };

  try {
    const [response] = await client.createConnection(request);

    console.log(`Successfully created connection: ${response.name}`);
    console.log(`Friendly name: ${response.friendlyName}`);

    console.log(`Service Account: ${response.cloudResource.serviceAccountId}`);
  } catch (err) {
    if (err.code === status.ALREADY_EXISTS) {
      console.log(`Connection '${connectionId}' already exists.`);
    } else {
      console.error(`Error creating connection: ${err.message}`);
    }
  }
}

Terraform

Use o recurso google_bigquery_connection.

Para autenticar no BigQuery, configure o Application Default Credentials. Para mais informações, acesse Configurar a autenticação para bibliotecas de cliente.

O exemplo a seguir cria uma conexão a recursos do Cloud chamada my_cloud_resource_connection na região US:


# This queries the provider for project information.
data "google_project" "default" {}

# This creates a cloud resource connection in the US region named my_cloud_resource_connection.
# Note: The cloud resource nested object has only one output field - serviceAccountId.
resource "google_bigquery_connection" "default" {
  connection_id = "my_cloud_resource_connection"
  project       = data.google_project.default.project_id
  location      = "US"
  cloud_resource {}
}

Para aplicar a configuração do Terraform em um projeto Google Cloud , siga as etapas nas seções a seguir.

Preparar o Cloud Shell

  1. Inicie o Cloud Shell.
  2. Defina o projeto Google Cloud padrão em que você quer aplicar as configurações do Terraform.

    Você só precisa executar esse comando uma vez por projeto, e ele pode ser executado em qualquer diretório.

    export GOOGLE_CLOUD_PROJECT=PROJECT_ID

    As variáveis de ambiente serão substituídas se você definir valores explícitos no arquivo de configuração do Terraform.

Preparar o diretório

Cada arquivo de configuração do Terraform precisa ter o próprio diretório, também chamado de módulo raiz.

  1. No Cloud Shell, crie um diretório e um novo arquivo dentro dele. O nome do arquivo precisa ter a extensão .tf, por exemplo, main.tf. Neste tutorial, o arquivo é chamado de main.tf.
    mkdir DIRECTORY && cd DIRECTORY && touch main.tf
  2. Se você estiver seguindo um tutorial, poderá copiar o exemplo de código em cada seção ou etapa.

    Copie o exemplo de código no main.tf recém-criado.

    Se preferir, copie o código do GitHub. Isso é recomendado quando o snippet do Terraform faz parte de uma solução de ponta a ponta.

  3. Revise e modifique os parâmetros de amostra para aplicar ao seu ambiente.
  4. Salve as alterações.
  5. Inicialize o Terraform. Você só precisa fazer isso uma vez por diretório.
    terraform init

    Opcionalmente, para usar a versão mais recente do provedor do Google, inclua a opção -upgrade:

    terraform init -upgrade

Aplique as alterações

  1. Revise a configuração e verifique se os recursos que o Terraform vai criar ou atualizar correspondem às suas expectativas:
    terraform plan

    Faça as correções necessárias na configuração.

  2. Para aplicar a configuração do Terraform, execute o comando a seguir e digite yes no prompt:
    terraform apply

    Aguarde até que o Terraform exiba a mensagem "Apply complete!".

  3. Abra seu Google Cloud projeto para conferir os resultados. No console do Google Cloud , navegue até seus recursos na UI para verificar se foram criados ou atualizados pelo Terraform.

Conceder acesso à conta de serviço da conexão

Você precisa do ID da conta de serviço que copiou anteriormente 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.

Para conceder à conta de serviço de conexão a 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.

  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 recurso do Cloud que você copiou anteriormente.

  5. No campo Selecionar um papel, escolha Service Usage e selecione Consumidor do Service Usage.

  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 recurso 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 chama o serviço do Cloud Translation

Em my_query_project, crie uma UDF em Python que chame o serviço Cloud Translation usando sua conexão a recursos do Cloud.

  1. No console do Google Cloud , acesse a página BigQuery.

    Acessar o BigQuery

  2. 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 dados
    • REGION.CONNECTION_ID: a região e o ID da sua conexão
  3. Clique em  Executar.

    A saída será semelhante a esta:

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

Práticas recomendadas

Ao criar UDFs em Python, siga estas práticas recomendadas:

  • Otimize a lógica de consulta para o agrupamento em lotes. Estruturas de consulta complexas podem desativar o agrupamento em lotes. Isso força um processamento lento, linha por linha, o que aumenta significativamente a latência em conjuntos de dados grandes.
  • Evite UDFs em expressões condicionais.
  • Evite usar UDFs para incorporar campos STRUCT diretamente.
  • Isole UDFs em projeções. Para garantir o agrupamento em lotes, execute a UDF em uma instrução SELECT usando uma expressão de tabela comum (CTE) ou uma subconsulta. Em seguida, faça filtros ou junções nesse resultado em uma etapa separada.
  • Otimize a carga útil de dados. O tamanho das linhas individuais pode afetar a eficiência do recurso de lote.
  • Minimize o tamanho da linha. Mantenha cada linha o menor possível para maximizar o número de linhas que podem ser processadas em um único lote.
  • Configure limites de contêineres com eficiência. A escalonabilidade é uma função da CPU, da memória e da simultaneidade de solicitações.
  • Ao usar o ajuste iterativo, comece com os valores padrão. Se o desempenho não for ideal, analise as métricas de monitoramento para identificar gargalos específicos.
  • Escalone seus recursos. Se as métricas de monitoramento mostrarem níveis altos de utilização, aumente a CPU e a memória alocadas.
  • Gerenciar dependências externas e confiabilidade. As UDFs que interagem com serviços externos exigem uma conexão e permissões adequadas.
  • Implemente tempos limite de API. Quando sua UDF do Python acessar a Internet, defina um tempo limite na chamada de API para evitar comportamentos inesperados. Um exemplo de acesso à Internet é a leitura de um bucket do Cloud Storage.

Ver métricas de UDF em Python

As UDFs em Python exportam métricas para o Cloud Monitoring. Essas métricas ajudam você a monitorar vários aspectos da integridade operacional e do consumo de recursos da sua UDF, fornecendo insights sobre a performance e o comportamento das instâncias de UDF.

Tipo de recurso de monitoramento

As métricas para UDFs do Python são informadas no seguinte tipo de recurso do Cloud Monitoring:

  • Tipo: bigquery.googleapis.com/ManagedRoutineInvocation
  • Nome de exibição: invocação de rotina gerenciada do BigQuery
  • Rótulos:
    • resource_container: o ID do projeto em que o job de consulta foi executado.
    • location: o local em que o job de consulta foi executado.
    • query_job_id: o ID do job de consulta que invocou a UDF do Python.
    • routine_project_id: o ID do projeto em que a rotina invocada é armazenada.
    • routine_dataset_id: o ID do conjunto de dados em que a rotina invocada está armazenada.
    • routine_id: o ID da rotina invocada.

Métricas

As seguintes métricas estão disponíveis para o tipo de recurso bigquery.googleapis.com/ManagedRoutineInvocation:

Métrica Descrição Unidade Tipo de valor
bigquery.googleapis.com/managed_routine/python/cpu_utilizations Quando uma UDF do Python é invocada, essa métrica mostra a distribuição da utilização da CPU em todas as instâncias de UDF do Python para o job de consulta. 102.% DISTRIBUTION
bigquery.googleapis.com/managed_routine/python/memory_utilizations Quando uma UDF do Python é invocada, essa métrica mostra a distribuição da utilização da memória em todas as instâncias de UDF do Python para o job de consulta. 102.% DISTRIBUTION
bigquery.googleapis.com/managed_routine/python/max_request_concurrencies Essa métrica mostra a distribuição do número máximo de solicitações simultâneas atendidas por cada instância de UDF em Python. Contagem DISTRIBUTION

Ver métricas

Para conferir as métricas das suas UDFs em Python, escolha uma das opções nas seções a seguir.

Detalhes do job

Para conferir as métricas de UDF do Python de um job de consulta específico, siga estas etapas:

  1. Acessar a página do BigQuery.

    Acessar o BigQuery

  2. Clique em Histórico de jobs.

  3. Na coluna código da tarefa, clique no ID da tarefa de consulta.

  4. Na página Detalhes do job de consulta, clique em Painel do Cloud Monitoring. Esse link mostra um painel filtrado para exibir as métricas de UDF em Python do job.

Metrics Explorer

Para conferir as métricas de UDFs do Python no Metrics Explorer, siga estas etapas:

  1. Acesse a página Metrics Explorer do Cloud Monitoring.

    Acessar o Metrics Explorer

  2. Clique em Selecionar uma métrica e, no campo Filtro, digite BigQuery Managed Routine Invocation ou bigquery.googleapis.com/ManagedRoutineInvocation.

  3. Escolha Rotina gerenciada do BigQuery > Managed_routine.

  4. Clique em qualquer uma das métricas disponíveis, como:

    • Uso da CPU da instância
    • Utilização da memória da instância
    • Máximo de solicitações simultâneas
  5. Clique em Aplicar.

    Por padrão, as métricas são mostradas em um gráfico.

  6. É possível filtrar e agrupar as métricas usando os rótulos definidos nos tipos de recursos do Monitoring. Para filtrar as métricas, siga estas etapas:

    1. No campo Filtro, escolha um tipo de recurso, como query_job_id ou routine_id.

    2. No campo Valor, insira o ID do job ou da rotina ou escolha um na lista.

Painéis do Cloud Monitoring

Para conferir as métricas de UDF do Python usando os painéis de monitoramento, siga estas etapas:

  1. Acesse a página Painéis do Cloud Monitoring.

    Ir para "Painéis"

  2. Clique no painel Monitoramento de consultas de rotina gerenciada do BigQuery.

    Esse painel oferece uma visão geral das principais métricas das suas UDFs.

  3. Para filtrar este painel, siga estas etapas:

    1. Clique em Filtrar.

    2. Na lista Filtrar por recurso, escolha uma opção, como ID do projeto, local, ID da rotina ou ID do job.

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 faturadas usando a SKU dos 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 em 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.

Cotas

Consulte Cotas e limites de UDF.