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 de 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.
- Las UDF de Python no son totalmente compatibles con las vistas de
INFORMATION_SCHEMA
. - No puedes crear ni actualizar una UDF de Python con la API de Routine.
- No se admiten los Controles del servicio de VPC.
- No se admiten las claves de encriptación administradas por el cliente (CMEK).
- No se admiten los siguientes tipos de datos:
JSON
,RANGE
,INTERVAL
yGEOGRAPHY
. - Los contenedores que ejecutan UDF de Python solo se pueden configurar hasta 2 CPU virtuales y 8 Gi.
Roles de IAM obligatorios
Los roles de IAM requeridos dependen de si eres propietario o usuario de una UDF de Python. Por lo general, el propietario de una UDF de Python crea o actualiza una UDF. Un usuario de una UDF de Python invoca una UDF creada por otra persona.
También se requieren roles adicionales si creas o ejecutas una UDF de Python que hace referencia a una conexión de recursos de Cloud.
Propietarios de UDF
Si creas o actualizas una UDF de Python, se deben otorgar los siguientes roles de IAM predefinidos en el recurso correspondiente:
Rol | Permisos necesarios | Recurso |
---|---|---|
Editor de datos de BigQuery (roles/bigquery.dataEditor )
|
|
Es el conjunto de datos en el que se crea o actualiza la UDF de Python. |
Usuario de trabajo de BigQuery (roles/bigquery.jobUser )
|
|
El proyecto en el que ejecutas la declaración CREATE FUNCTION .
|
Administrador de conexión de BigQuery (roles/bigquery.connectionAdmin )
|
|
Es la conexión a la que le otorgas acceso a un recurso externo. Esta conexión solo es necesaria si tu UDF usa la cláusula WITH CONNECTION para acceder a un servicio externo.
|
Usuarios de UDF
Si invocas una UDF de Python, se deben otorgar los siguientes roles de IAM predefinidos en el recurso correspondiente:
Rol | Permisos necesarios | Recurso |
---|---|---|
Usuario de BigQuery (roles/bigquery.user ) |
bigquery.jobs.create para ejecutar un trabajo de consulta que haga referencia a la UDF. |
Es el proyecto en el que ejecutas un trabajo de consulta que invoca la UDF de Python. |
Visualizador de datos de BigQuery (roles/bigquery.dataViewer ) |
bigquery.routines.get para ejecutar una UDF creada por otra persona. |
Es el conjunto de datos en el que se almacena la UDF de Python. |
Usuario de conexión de BigQuery (roles/bigquery.connectionUser ) |
bigquery.connections.use para ejecutar una UDF de Python que hace referencia a una conexión de recursos de Cloud |
Es la conexión de recursos de Cloud a la que hace referencia la UDF de Python. Esta conexión solo es obligatoria si tu UDF hace referencia a una conexión. |
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 entre comillas.
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 espython-3.11
. Para obtener una lista completa de las opciones disponibles, consulta la lista de opciones de la función para la instrucciónCREATE 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 declaración DROP FUNCTION
.
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
podría esperar automáticamente a que se complete la imagen. Sin dependencias externas, la imagen del contenedor se debería crear en menos de un minuto.
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 llama a la UDF desde una sentencia SELECT
:
Ve a la página de BigQuery.
En el editor de consultas, ingresa la siguiente declaración
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.
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 DataFrames de BigQuery para convertir una función personalizada en una UDF de Python:
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.
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 que se incluirán en el lote se determinará automáticamente.
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
:
Ve a la página de BigQuery.
En el editor de consultas, ingresa la siguiente declaración
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.
Haz clic en
Ejecutar.
Tipos de datos de UDF de Python admitidos
En la siguiente tabla, se define la asignación entre los tipos de datos de BigQuery, los tipos de datos de Python y los tipos de datos de Pandas:
Tipo de datos de BigQuery | Tipo de datos integrado de Python que usa la UDF estándar | Tipo de datos de Pandas que usa la UDF vectorizada | Tipo de datos de PyArrow que se usa para ARRAY y STRUCT en la UDF vectorizada |
---|---|---|---|
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 función: Valor que devuelve la función: |
Parámetro de la función: Valor de retorno de la función: |
TimestampType(timestamp[us]) , con zona horaria |
DATE |
datetime.date |
date32[pyarrow] |
DataType(date32[day]) |
TIME |
datetime.time |
time64[pyarrow] |
Time64Type(time64[us]) |
DATETIME |
datetime.datetime (sin zona horaria) |
timestamp[us][pyarrow] |
TimestampType(timestamp[us]) , sin zona horaria |
ARRAY |
list |
list<...>[pyarrow] , en el que el tipo de datos del elemento es pandas.ArrowDtype |
ListType |
STRUCT |
dict |
struct<...>[pyarrow] , en el que el tipo de datos del campo es pandas.ArrowDtype |
StructType |
Versiones de entorno de ejecución compatibles
Las UDF de Python de BigQuery admiten el tiempo de ejecución de python-3.11
. Esta versión de Python incluye algunos paquetes preinstalados adicionales. En el caso de las bibliotecas del sistema, verifica la imagen base del entorno de ejecución.
Versión de entorno de ejecución | Versión de Python | Incluye | Imagen base del entorno de ejecución |
---|---|---|---|
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 |
Usa paquetes de terceros
Puedes usar la lista de opciones de CREATE FUNCTION
para usar módulos que no sean los que proporciona la biblioteca estándar de Python y los paquetes preinstalados. Puedes instalar paquetes desde el índice de paquetes de Python (PyPI) o importar archivos de Python desde Cloud Storage.
Instala un paquete desde el índice de paquetes de Python
Cuando instalas un paquete, debes proporcionar su nombre y, de manera opcional, puedes proporcionar su versión con los especificadores de versión de paquetes de Python.
Si el paquete está en el entorno de ejecución, se usa ese paquete, a menos que se especifique una versión en particular en la lista de opciones CREATE FUNCTION
. Si no se especifica una versión del paquete y este no se encuentra en el tiempo de ejecución, se usa la versión disponible más reciente. Solo se admiten los paquetes con el formato binario de ruedas.
En el siguiente ejemplo, se muestra cómo crear una UDF de Python que instala el paquete scipy
con la lista de opciones CREATE OR REPLACE FUNCTION
:
Ve a la página de BigQuery.
En el editor de consultas, ingresa la siguiente declaración
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);
Reemplaza PROJECT_ID.DATASET_ID con el ID de tu proyecto y el ID del conjunto de datos.
Haz clic en
Ejecutar.
Importa archivos de Python adicionales como bibliotecas
Puedes extender tus UDF de Python con la lista de opciones de funciones importando archivos de Python desde Cloud Storage.
En el código Python de tu UDF, puedes importar los archivos Python desde Cloud Storage como módulos con la instrucción import seguida de la ruta de acceso al objeto de Cloud Storage. Por ejemplo, si importas gs://BUCKET_NAME/path/to/lib1.py
, tu instrucción de importación sería import path.to.lib1
.
El nombre de archivo de Python debe ser un identificador de Python. Cada nombre de folder
en el nombre del objeto (después del /
) debe ser un identificador de Python válido. Dentro del rango ASCII (U+0001…U+007F), se pueden usar los siguientes caracteres en los identificadores:
- Letras mayúsculas y minúsculas de la A a la Z
- Guiones bajos
- Los dígitos del cero al nueve, pero un número no puede aparecer como el primer carácter del identificador.
En el siguiente ejemplo, se muestra cómo crear una UDF de Python que importa el paquete de la biblioteca cliente lib1.py
desde un bucket de Cloud Storage llamado my_bucket
:
Ve a la página de BigQuery.
En el editor de consultas, ingresa la siguiente declaración
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); """;
Reemplaza PROJECT_ID.DATASET_ID con el ID de tu proyecto y el ID del conjunto de datos.
Haz clic en
Ejecutar.
Configura límites de contenedores para las UDF de Python
Puedes usar la lista de opciones CREATE FUNCTION
para especificar los límites de CPU y memoria de los contenedores que ejecutan UDF de Python.
De forma predeterminada, la memoria asignada a cada instancia de contenedor es de 512 MiB y la CPU asignada es de 0.33 vCPU.
En el siguiente ejemplo, se crea una UDF de Python con la lista de opciones CREATE FUNCTION
para especificar los límites del contenedor:
Ve a la página de BigQuery.
En el editor de consultas, ingresa la siguiente declaración
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() """;
Reemplaza PROJECT_ID.DATASET_ID con el ID de tu proyecto y el ID del conjunto de datos.
Haz clic en
Ejecutar.
Valores de CPU admitidos
Las UDF de Python admiten valores de CPU fraccionarios entre 0.33
y 1.0
, y valores de CPU no fraccionarios de 1
y 2
. Los valores de entrada fraccionarios se redondean a dos decimales antes de aplicarse al contenedor.
Valores de memoria admitidos
Los contenedores de UDF de Python admiten valores de memoria en el siguiente formato: <integer_number><unit>
. La unidad debe ser uno de los siguientes valores: Mi
, M
, Gi
, G
. La cantidad mínima de memoria que puedes configurar es de 256 mebibytes (256 Mi).
La cantidad máxima de memoria que puedes configurar es de 8 gibibytes (8 Gi).
Según el valor de memoria que elijas, también debes especificar la cantidad mínima de CPU. En la siguiente tabla, se muestran los valores mínimos de CPU para cada valor de memoria:
Memoria | 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 |
Llama a Trusted Cloud by S3NS servicios en línea en código Python
Una UDF de Python accede a un servicio Trusted Cloud by S3NS o a un servicio externo a través de la cuenta de servicio de conexión de recursos de Cloud. Se deben otorgar permisos a la cuenta de servicio de la conexión para acceder al servicio. Los permisos necesarios varían según el servicio al que se accede y las APIs a las que se llama desde tu código de Python.
Si creas una UDF de Python sin usar una conexión de recursos de Cloud, la función se ejecutará en un entorno que bloquea el acceso a la red. Si tu UDF accede a servicios en línea, debes crearla con una conexión de recursos de Cloud. Si no lo haces, la UDF no podrá acceder a la red hasta que se alcance un tiempo de espera de conexión interno.
En el siguiente ejemplo, se muestra cómo acceder al servicio de Cloud Translation desde una UDF de Python. En este ejemplo, hay dos proyectos: uno llamado my_query_project
en el que creas la UDF y la conexión de recursos de Cloud, y otro en el que ejecutas Cloud Translation llamado my_translate_project
.
Crea una conexión de recurso de Cloud
Primero, crea una conexión de recursos de Cloud en my_query_project
. Para crear la conexión de recursos de Cloud, sigue los pasos que se indican en la página Crea una conexión de recursos de Cloud.
Después de crear la conexión, ábrela y, en el panel Información de conexión, copia el ID de la cuenta de servicio. Necesitarás este ID cuando configures los permisos para la conexión. Cuando creas un recurso de conexión, BigQuery crea una cuenta de servicio del sistema única y la asocia con la conexión.
Otorga acceso a la cuenta de servicio de la conexión
Para otorgar a la cuenta de servicio de conexión de recursos de Cloud acceso a tus proyectos, otórgale el rol de consumidor de uso del servicio (roles/serviceusage.serviceUsageConsumer
) en my_query_project
y el rol de usuario de la API de Cloud Translation (roles/cloudtranslate.user
) en my_translate_project
.
Ir a la página IAM.
Verifica que
my_query_project
esté seleccionado.Haz clic en
Otorgar acceso.En el campo Principales nuevas, ingresa el ID de la cuenta de servicio de la conexión de recurso de Cloud que copiaste antes.
En el campo Selecciona un rol, elige Uso del servicio y, luego, selecciona Consumidor de uso del servicio.
Haz clic en Guardar.
En el selector de proyectos, elige
my_translate_project
.Ir a la página IAM.
Haz clic en
Otorgar acceso.En el campo Principales nuevas, ingresa el ID de la cuenta de servicio de la conexión de recurso de Cloud que copiaste antes.
En el campo Selecciona un rol, elige Cloud Translation y, luego, selecciona Usuario de la API de Cloud Translation.
Haz clic en Guardar.
Crea una UDF de Python que llame al servicio de Cloud Translation
En my_query_project
, crea una UDF de Python que llame al servicio de Cloud Translation con tu conexión de recursos de Cloud.
Ve a la página de BigQuery.
Ingresa la siguiente sentencia
CREATE FUNCTION
en el 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;
Reemplaza lo siguiente:
PROJECT_ID.DATASET_ID
: Tu ID del proyecto y el ID del conjunto de datosREGION.CONNECTION_ID
: La región y el ID de tu conexión
Haz clic en
Ejecutar.El resultado debe verse de la siguiente manera:
+--------------------------+-------------------------------+ | text | translated_text | +--------------------------+-------------------------------+ | Hello | Hola | | Good morning | Buen dia | | Goodbye | Adios | +--------------------------+-------------------------------+
Ubicaciones admitidas
Las UDF de Python son compatibles con todas las ubicaciones regionales y multirregionales de BigQuery.
Precios
Las UDF de Python se ofrecen sin cargos adicionales.
Cuando la facturación está habilitada, se aplican las siguientes condiciones:
- Los cargos por las UDF de Python se facturan con el SKU de los servicios de BigQuery.
- Los cargos son proporcionales a la cantidad de procesamiento y memoria que se consumen cuando se invoca la UDF de Python.
- A los clientes de UDF de Python también se les cobra el costo de compilar o recompilar la imagen del contenedor de la UDF. Este cargo es proporcional a los recursos que se usan para compilar la imagen con el código y las dependencias del cliente.
- Si las UDF de Python generan salida de red externa o de Internet, también verás un cargo de salida de Internet del nivel Premium de Cloud Networking.