Trabaja con funciones definidas por el usuario en Python

Una función definida por el usuario (UDF) de Python te permite implementar una función escalar en Python y usarla en una consulta en SQL. Las UDF de Python son similares a las UDF de SQL y JavaScript, pero con capacidades adicionales. Las UDF de Python te permiten instalar bibliotecas de terceros desde el índice de paquetes de Python (PyPI) y acceder a servicios externos con una conexión a recursos de Cloud.

Las UDF de Python se compilan y ejecutan en recursos administrados de BigQuery.

Limitaciones

  • python-3.11 es el único tiempo de ejecución compatible.
  • No puedes crear una UDF de Python temporal.
  • No puedes usar una UDF de Python con una vista materializada.
  • Los resultados de una consulta que llama a una UDF de Python no se almacenan en caché porque siempre se supone que el valor de retorno de una UDF de Python no es determinista.
  • No se admiten las cargas de trabajo certificadas.
  • No se admiten los siguientes tipos de datos: JSON, RANGE, INTERVAL y GEOGRAPHY.
  • Los contenedores que ejecutan UDF de Python solo se pueden configurar con hasta 4 CPU virtuales y 16 GiB.
  • No se admite la encriptación del código de las UDF de Python con claves de encriptación administradas por el cliente (CMEK).
  • Las UDF de Python admiten los Controles del servicio de VPC, pero no las redes de VPC.

Roles obligatorios

Los roles de IAM requeridos dependen de si eres propietario o usuario de una UDF de Python.

Propietarios de UDF

Por lo general, el propietario de una UDF de Python crea o actualiza una UDF. También se requieren roles adicionales si creas una UDF de Python que hace referencia a una conexión a recursos de Cloud. Esta conexión solo es necesaria si tu UDF usa la cláusula WITH CONNECTION para acceder a un servicio externo.

Para obtener los permisos que necesitas para crear o actualizar una UDF de Python, pídele a tu administrador que te otorgue los siguientes roles de IAM:

Para obtener más información sobre cómo otorgar roles, consulta Administra el acceso a proyectos, carpetas y organizaciones.

Estos roles predefinidos contienen los permisos necesarios para crear o actualizar una UDF de Python. Para ver los permisos exactos que son necesarios, expande la sección Permisos requeridos:

Permisos necesarios

Se requieren los siguientes permisos para crear o actualizar una UDF de Python:

  • Crea una UDF de Python con la instrucción CREATE FUNCTION: bigquery.routines.create en el conjunto de datos
  • Actualiza una UDF de Python con la sentencia CREATE FUNCTION: bigquery.routines.update en el conjunto de datos
  • Ejecuta un trabajo de consulta de la instrucción CREATE FUNCTION: bigquery.jobs.create en el proyecto
  • Crea una nueva conexión de recurso de Cloud: bigquery.connections.create en el proyecto.
  • Usa una conexión en la instrucción CREATE FUNCTION: bigquery.connections.delegate en la conexión

También puedes obtener estos permisos con roles personalizados o con otros roles predefinidos.

Para obtener más información sobre los roles en BigQuery, consulta Roles de IAM predefinidos.

Usuarios de UDF

Un usuario de una UDF de Python invoca una UDF creada por otra persona. También se requieren roles adicionales si invocas una UDF de Python que hace referencia a una conexión de recursos de Cloud.

Para obtener los permisos que necesitas para invocar una UDF de Python creada por otra persona, pídele a tu administrador que te otorgue los siguientes roles de IAM:

Para obtener más información sobre cómo otorgar roles, consulta Administra el acceso a proyectos, carpetas y organizaciones.

Estos roles predefinidos contienen los permisos necesarios para invocar una UDF de Python creada por otra persona. Para ver los permisos exactos que son necesarios, expande la sección Permisos requeridos:

Permisos necesarios

Se requieren los siguientes permisos para invocar una UDF de Python creada por otra persona:

  • Para ejecutar un trabajo de consulta que haga referencia a una UDF de Python, haz lo siguiente:bigquery.jobs.create en el proyecto
  • Para invocar una UDF de Python creada por otra persona, sigue estos pasos: bigquery.routines.get en el conjunto de datos
  • Para ejecutar una UDF de Python que haga referencia a una conexión a recursos de Cloud, haz lo siguiente: bigquery.connections.use en la conexión

También puedes obtener estos permisos con roles personalizados o con otros roles predefinidos.

Para obtener más información sobre los roles en BigQuery, consulta Roles de IAM predefinidos.

Crea una UDF de Python persistente

Sigue estas reglas cuando crees una UDF de Python:

  • El cuerpo de la UDF de Python debe ser un literal de cadena entre comillas que represente el código de Python. Para obtener más información sobre los literales de cadena entre comillas, consulta Formatos para literales entrecomillados.

  • El cuerpo de la UDF de Python debe incluir una función de Python que se use en el argumento entry_point de la lista de opciones de la UDF de Python.

  • Se debe especificar una versión del entorno de ejecución de Python en la opción runtime_version. La única versión del entorno de ejecución de Python compatible es python-3.11. Para obtener una lista completa de las opciones disponibles, consulta la lista de opciones de la función para la declaración CREATE FUNCTION.

Para crear una UDF de Python persistente, usa la declaración CREATE FUNCTION sin la palabra clave TEMP o TEMPORARY. Para borrar una UDF de Python persistente, usa la sentencia DROP FUNCTION.

Ejemplo

Para ver un ejemplo de cómo crear una UDF de Python persistente, elige una de las siguientes opciones:

Console

En el siguiente ejemplo, se crea una UDF de Python persistente llamada multiplyInputs y se la llama desde una declaración SELECT:

  1. Ve a la página de BigQuery.

    Ir a BigQuery

  2. En el editor de consultas, ingresa la siguiente sentencia 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;

    Reemplaza PROJECT_ID.DATASET_ID con el ID de tu proyecto y el ID del conjunto de datos.

  3. Haz clic en  Ejecutar.

    En este ejemplo, se produce el siguiente resultado:

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

Permite trabajar con BigQuery DataFrames.

En el siguiente ejemplo, se usan BigQuery DataFrames para convertir una función personalizada en una UDF de 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}")

Estado de compilación del contenedor

Cuando creas una UDF de Python con la instrucción CREATE FUNCTION, BigQuery crea o actualiza una imagen de contenedor basada en una imagen base. El contenedor se compila en la imagen base con tu código y las dependencias de paquetes especificadas.

La creación del contenedor es un proceso de larga duración. La primera consulta después de ejecutar la instrucción CREATE FUNCTION espera a que se complete la compilación de la imagen. Si no hay dependencias externas, la imagen de contenedor suele crearse en menos de un minuto.

El tamaño de todos los contenedores de UDF de Python por proyecto y por región se limita a un total de 10 GiB. Para obtener más información, consulta Límites de las funciones definidas por el usuario para las UDF persistentes. La compilación del contenedor fallará si tu proyecto alcanzó la cuota.

Para ver el estado de la compilación de tu contenedor, elige una de las siguientes opciones:

Console

  1. Ve a la página de BigQuery Studio.

    Ir a Studio

  2. En el panel izquierdo, expande tu proyecto y, luego, haz clic en Conjuntos de datos.

  3. Haz clic en el vínculo para abrir el conjunto de datos que contiene tu UDF de Python.

  4. En la página del conjunto de datos, haz clic en la pestaña Rutinas.

  5. En la columna ID de rutina, haz clic en tu UDF de Python.

  6. En la página Información sobre la función persistente, puedes ver el estado de la compilación, la duración de la compilación y el tamaño de la imagen. El estado de la compilación es uno de los siguientes:

    • En curso
    • Correcto
    • Con errores

    Si falla una compilación, la página de información de la función proporciona mensajes de error detallados para que puedas solucionar problemas, como errores de sintaxis o problemas para instalar paquetes externos.

    Página Información sobre la función persistente en la consola.

SQL

Para consultar los campos de estado de compilación en la vista INFORMATION_SCHEMA.ROUTINES, sigue estos pasos:

  1. Ve a la página de BigQuery Studio.

    Ir a Studio

  2. Cambia al editor de consultas o haz clic en Consulta en SQL.

  3. Ingresa la siguiente consulta para recuperar los campos BUILD_STATUS de la vista INFORMATION_SCHEMA.ROUTINES. La columna BUILD_STATUS es un tipo STRUCT en GoogleSQL:

    SELECT
      build_status.*
    FROM
      `PROJECT_ID.DATASET_ID`.INFORMATION_SCHEMA.ROUTINES;
    

    Reemplaza PROJECT_ID.DATASET_ID con el ID de tu proyecto y el ID del conjunto de datos.

    El resultado debe tener el siguiente aspecto. Se omiten los campos de error:

    +---------------+--------------------------------+------------------------+------------------+
    | build_state   | build_state_update_time        | build_duration_seconds | image_size_bytes |
    +---------------+--------------------------------+------------------------+------------------+
    | SUCCEEDED     | 2026-05-14 17:21:49.736000 UTC |                     11 |             3167 |
    +---------------+--------------------------------+------------------------+------------------+
    

API

Consulta el estado de compilación del contenedor con RoutineBuildStatus en la API.

Crea una UDF de Python vectorizada

Puedes implementar tu UDF de Python para procesar un lote de filas en lugar de una sola fila usando la vectorización. La vectorización puede mejorar el rendimiento de las consultas. Puedes crear una UDF vectorizada con Pandas o Apache Arrow.

Para controlar el comportamiento del procesamiento por lotes, especifica la cantidad máxima de filas en cada lote con la opción max_batching_rows en la lista de opciones de CREATE OR REPLACE FUNCTION. Si especificas max_batching_rows, BigQuery determina la cantidad de filas en un lote, hasta el límite de max_batching_rows. Si no se especifica max_batching_rows, la cantidad de filas para el procesamiento por lotes se determina automáticamente.

Cómo usar Pandas

Una UDF de Python vectorizada tiene un solo argumento pandas.DataFrame que debe anotarse. El argumento pandas.DataFrame tiene la misma cantidad de columnas que los parámetros de la UDF de Python definidos en la instrucción CREATE FUNCTION. Los nombres de las columnas en el argumento pandas.DataFrame tienen los mismos nombres que los parámetros de la UDF.

Tu función debe devolver un pandas.Series o un pandas.DataFrame de una sola columna con la misma cantidad de filas que la entrada.

En el siguiente ejemplo, se crea una UDF de Python vectorizada llamada multiplyInputs con dos parámetros: x y y:

  1. Ve a la página de BigQuery.

    Ir a BigQuery

  2. En el editor de consultas, ingresa la siguiente sentencia 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']
    
    ''';

    Reemplaza PROJECT_ID.DATASET_ID con el ID de tu proyecto y el ID del conjunto de datos.

    Llamar a la UDF es igual que en el ejemplo anterior.

  3. Haz clic en  Ejecutar.

Usa Apache Arrow

En el siguiente ejemplo, se usa la interfaz RecordBatch de Apache Arrow. Cuando usas la interfaz RecordBatch, la función pasa un lote de filas de columnas de igual longitud al punto de entrada. En el siguiente ejemplo, se usa Apache Arrow para crear una UDF de Python vectorizada llamada multiplyVectorizedArrow.

  1. Ve a la página de BigQuery.

    Ir a BigQuery

  2. En el editor de consultas, ingresa la siguiente sentencia CREATE FUNCTION:

    CREATE FUNCTION `PROJECT_ID.DATASET_ID`.multiplyVectorizedArrow