Utilizzare le funzioni definite dall'utente in Python

Una funzione definita dall'utente (UDF) Python consente di implementare una funzione scalare in Python e utilizzarla in una query SQL. Le funzioni definite dall'utente Python sono simili alle funzioni definite dall'utente SQL e JavaScript, ma con funzionalità aggiuntive. Le UDF Python ti consentono di installare librerie di terze parti da Python Package Index (PyPI) e di accedere a servizi esterni utilizzando una connessione alle risorse Cloud.

Le UDF Python vengono create ed eseguite su risorse gestite da BigQuery.

Limitazioni

  • python-3.11 è l'unico runtime supportato.
  • Non puoi creare una UDF Python temporanea.
  • Non puoi utilizzare una UDF Python con una vista materializzata.
  • I risultati di una query che chiama una funzione definita dall'utente Python non vengono memorizzati nella cache perché si presume sempre che il valore restituito di una funzione definita dall'utente Python non sia deterministico.
  • Assured Workloads non è supportato.
  • Questi tipi di dati non sono supportati: JSON, RANGE, INTERVAL e GEOGRAPHY.
  • I container che eseguono UDF Python possono essere configurati solo fino a 4 vCPU e 16 GiB.
  • La crittografia del codice UDF Python con chiavi di crittografia gestite dal cliente (CMEK) non è supportata.
  • Le UDF Python supportano i Controlli di servizio VPC, ma le reti VPC non sono supportate.

Ruoli obbligatori

I ruoli IAM richiesti dipendono dal fatto che tu sia il proprietario o l'utente di una UDF Python.

Proprietari UDF

In genere, il proprietario di una funzione definita dall'utente Python crea o aggiorna una funzione definita dall'utente. Sono necessari anche ruoli aggiuntivi se crei una UDF Python che fa riferimento a una connessione alle risorse Cloud. Questa connessione è necessaria solo se la tua UDF utilizza la clausola WITH CONNECTION per accedere a un servizio esterno.

Per ottenere le autorizzazioni necessarie per creare o aggiornare una UDF Python, chiedi all'amministratore di concederti i seguenti ruoli IAM:

Per saperne di più sulla concessione dei ruoli, consulta Gestisci l'accesso a progetti, cartelle e organizzazioni.

Questi ruoli predefiniti contengono le autorizzazioni necessarie per creare o aggiornare una UDF Python. Per vedere quali sono esattamente le autorizzazioni richieste, espandi la sezione Autorizzazioni obbligatorie:

Autorizzazioni obbligatorie

Per creare o aggiornare una UDF Python sono necessarie le seguenti autorizzazioni:

  • Crea una UDF Python utilizzando l'istruzione CREATE FUNCTION: bigquery.routines.create sul set di dati
  • Aggiorna una funzione definita dall'utente Python utilizzando l'istruzione CREATE FUNCTION: bigquery.routines.update sul set di dati
  • Esegui un job di query dell'istruzione CREATE FUNCTION: bigquery.jobs.create sul progetto
  • Crea una nuova connessione risorsa Cloud: bigquery.connections.create sul progetto
  • Utilizza una connessione nell'istruzione CREATE FUNCTION: bigquery.connections.delegate sulla connessione

Potresti anche ottenere queste autorizzazioni con ruoli personalizzati o altri ruoli predefiniti.

Per saperne di più sui ruoli in BigQuery, vedi Ruoli IAM predefiniti.

utenti UDF

Un utente UDF Python richiama una UDF creata da un altro utente. Sono necessari anche ruoli aggiuntivi se richiami una UDF Python che fa riferimento a una connessione a una risorsa cloud.

Per ottenere le autorizzazioni necessarie per richiamare una UDF Python creata da un altro utente, chiedi all'amministratore di concederti i seguenti ruoli IAM:

Per saperne di più sulla concessione dei ruoli, consulta Gestisci l'accesso a progetti, cartelle e organizzazioni.

Questi ruoli predefiniti contengono le autorizzazioni necessarie per richiamare una UDF Python creata da un altro utente. Per vedere quali sono esattamente le autorizzazioni richieste, espandi la sezione Autorizzazioni obbligatorie:

Autorizzazioni obbligatorie

Per richiamare una UDF Python creata da un altro utente sono necessarie le seguenti autorizzazioni:

  • Per eseguire un job di query che fa riferimento a una UDF Python: bigquery.jobs.create sul progetto
  • Per richiamare una UDF Python creata da un altro utente: bigquery.routines.get sul set di dati
  • Per eseguire una funzione definita dall'utente Python che fa riferimento a una connessione alle risorse Cloud: bigquery.connections.use sulla connessione

Potresti anche ottenere queste autorizzazioni con ruoli personalizzati o altri ruoli predefiniti.

Per saperne di più sui ruoli in BigQuery, vedi Ruoli IAM predefiniti.

Crea una funzione definita dall'utente Python permanente

Segui queste regole quando crei una funzione definita dall'utente Python:

  • Il corpo della UDF Python deve essere un valore letterale stringa tra virgolette che rappresenta il codice Python. Per scoprire di più sui valori letterali stringa tra virgolette, consulta Formati per i valori letterali tra virgolette.

  • Il corpo della UDF Python deve includere una funzione Python utilizzata nell'argomento entry_point nell'elenco delle opzioni della UDF Python.

  • È necessario specificare una versione del runtime Python nell'opzione runtime_version. L'unica versione del runtime Python supportata è python-3.11. Per un elenco completo delle opzioni disponibili, consulta l'elenco delle opzioni di funzione per l'istruzione CREATE FUNCTION.

Per creare una UDF Python persistente, utilizza l'istruzione CREATE FUNCTION senza la parola chiave TEMP o TEMPORARY. Per eliminare una UDF Python permanente, utilizza l'istruzione DROP FUNCTION.

Esempio

Per visualizzare un esempio di creazione di una UDF Python persistente, scegli una delle seguenti opzioni:

Console

L'esempio seguente crea una funzione definita dall'utente Python permanente denominata multiplyInputs e la chiama da un'istruzione SELECT:

  1. Vai alla pagina BigQuery.

    Vai a BigQuery

  2. Nell'editor di query, inserisci la seguente istruzione 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;

    Sostituisci PROJECT_ID.DATASET_ID con l'ID progetto e l'ID set di dati.

  3. Fai clic su  Esegui.

    Questo esempio produce il seguente output:

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

BigQuery DataFrames

L'esempio seguente utilizza BigQuery DataFrames per trasformare una funzione personalizzata in una UDF 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}")

Stato di Container Build

Quando crei una funzione definita dall'utente Python utilizzando l'istruzione CREATE FUNCTION, BigQuery crea o aggiorna un'immagine container basata su un'immagine di base. Il container viene creato sull'immagine di base utilizzando il tuo codice e le dipendenze dei pacchetti specificate.

La creazione del contenitore è un processo di lunga durata. La prima query dopo l'esecuzione dell'istruzione CREATE FUNCTION attende il completamento della build dell'immagine. Se non ci sono dipendenze esterne, l'immagine container viene in genere creata in meno di un minuto.

La dimensione di tutti i container UDF Python per progetto e per regione è limitata a un totale di 10 GiB. Per saperne di più, consulta Limiti delle funzioni definite dall'utente per le funzioni definite dall'utente permanenti. La build del container non riesce se il progetto ha raggiunto la quota.

Per visualizzare lo stato della build del contenitore, scegli una delle seguenti opzioni:

Console

  1. Vai alla pagina BigQuery Studio.

    Vai a Studio

  2. Nel riquadro a sinistra, espandi il progetto e fai clic su Set di dati.

  3. Fai clic sul link per aprire il set di dati che contiene la tua UDF Python.

  4. Nella pagina del set di dati, fai clic sulla scheda Routine.

  5. Nella colonna ID routine, fai clic sulla UDF Python.

  6. Nella pagina Informazioni funzione permanente puoi visualizzare lo stato della build, la durata della build e le dimensioni dell'immagine. Lo stato della build è uno dei seguenti:

    • In corso
    • Riuscito
    • Non riuscito

    Se una build non va a buon fine, la pagina delle informazioni sulla funzione fornisce messaggi di errore dettagliati in modo da poter risolvere problemi come errori di sintassi o problemi di installazione di pacchetti esterni.

    La pagina Informazioni funzione permanente nella console.

SQL

Per eseguire query sui campi dello stato della build nella visualizzazione INFORMATION_SCHEMA.ROUTINES:

  1. Vai alla pagina BigQuery Studio.

    Vai a Studio

  2. Passa all'editor di query o fai clic su Query SQL.

  3. Inserisci la seguente query per recuperare i campi BUILD_STATUS dalla visualizzazione INFORMATION_SCHEMA.ROUTINES. La colonna BUILD_STATUS è un tipo STRUCT in GoogleSQL:

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

    Sostituisci PROJECT_ID.DATASET_ID con l'ID progetto e l'ID set di dati.

    L'output dovrebbe essere simile al seguente. I campi di errore vengono omessi:

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

API

Visualizza lo stato della build del container utilizzando RoutineBuildStatus nell'API.

Crea una funzione definita dall'utente Python vettorizzata

Puoi implementare la tua funzione definita dall'utente Python per elaborare un batch di righe anziché una singola riga utilizzando la vettorizzazione. La vettorizzazione può migliorare le prestazioni delle query. Puoi creare una funzione definita dall'utente vettorizzata utilizzando Pandas o Apache Arrow.

Per controllare il comportamento del batch, specifica il numero massimo di righe in ogni batch utilizzando l'opzione max_batching_rows nell'elenco di opzioni CREATE OR REPLACE FUNCTION. Se specifichi max_batching_rows, BigQuery determina il numero di righe in un batch, fino al limite di max_batching_rows. Se max_batching_rows non è specificato, il numero di righe da raggruppare viene determinato automaticamente.

Utilizzare Pandas

Una UDF Python vettorizzata ha un singolo argomento pandas.DataFrame che deve essere annotato. L'argomento pandas.DataFrame ha lo stesso numero di colonne dei parametri UDF Python definiti nell'istruzione CREATE FUNCTION. I nomi delle colonne nell'argomento pandas.DataFrame hanno gli stessi nomi dei parametri della funzione definita dall'utente.

La funzione deve restituire un pandas.Series o un pandas.DataFrame a una sola colonna con lo stesso numero di righe dell'input.

Il seguente esempio crea una funzione definita dall'utente Python vettorizzata denominata multiplyInputs con due parametri: x e y:

  1. Vai alla pagina BigQuery.

    Vai a BigQuery

  2. Nell'editor di query, inserisci la seguente istruzione 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']
    
    ''';

    Sostituisci PROJECT_ID.DATASET_ID con l'ID progetto e l'ID set di dati.

    La chiamata alla UDF è la stessa dell'esempio precedente.

  3. Fai clic su  Esegui.

Utilizzare Apache Arrow

L'esempio seguente utilizza l'interfaccia RecordBatch di Apache Arrow. Quando utilizzi l'interfaccia RecordBatch, la funzione passa un batch di righe di colonne di uguale lunghezza al punto di ingresso. L'esempio seguente utilizza Apache Arrow per creare una UDF Python vettorizzata denominata multiplyVectorizedArrow.

  1. Vai alla pagina BigQuery.

    Vai a BigQuery

  2. Nell'editor di query, inserisci la seguente istruzione 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)
    ''';

    Sostituisci PROJECT_ID.DATASET_ID con l'ID progetto e l'ID set di dati.

    La chiamata alla UDF è la stessa degli esempi precedenti.

  3. Fai clic su  Esegui.

Richiamare una funzione definita dall'utente Python

Se hai l'autorizzazione per richiamare una funzione definita dall'utente Python, puoi chiamarla come qualsiasi altra funzione. Per utilizzare una funzione definita in un progetto diverso, utilizza il nome completo della funzione. Ad esempio, per chiamare una funzione di estrazione XML denominata cw_xml_extract in un altro progetto, completa i seguenti passaggi.

Console

  1. Vai alla pagina BigQuery.

    Vai a BigQuery

  2. Nell'editor di query, inserisci il seguente esempio:

    SELECT
      `PROJECT_ID.DATASET_ID`.`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),