Creazione di una data lakehouse unificata per l'AI con Apache Iceberg e BigLake

1. Introduzione

In questo codelab esplorerai le funzionalità del data lakehouse unificato su Google Cloud. Interagirai con i set di dati pubblici forniti tramite il catalogo REST Apache Iceberg su BigLake e poi applicherai le funzionalità di AI di Google Cloud ai dati strutturati e non strutturati.

Eseguirai query sul set di dati classico NYC Taxi utilizzando Apache Iceberg, approfondirai Time Travel per controllare le modifiche ai dati e poi utilizzerai BigQuery ML e Gemini per eseguire modelli di AI sui tuoi dati.

In questo lab proverai a:

  • Utilizza Google Cloud Serverless per Apache Spark per eseguire query sui set di dati pubblici Apache Iceberg ospitati su BigLake.
  • Esegui query sui dati strutturati nel formato Apache Iceberg.
  • Dimostra la funzionalità Time Travel in Apache Iceberg.
  • Utilizza BigQuery ML per addestrare un modello predittivo su dati strutturati.
  • Crea una tabella degli oggetti BigLake (dati non strutturati) e utilizza Gemini per analizzare le immagini.

Che cosa ti serve

  • Un browser web come Chrome.
  • Un progetto Google Cloud con la fatturazione abilitata.

Costo e durata previsti

  • Tempo di completamento: circa 45 minuti.
  • Costo stimato: < 2 €. Utilizziamo set di dati pubblici e query serverless per contenere i costi.

2. Configurazione e requisiti

In questo passaggio, preparerai l'ambiente e abiliterai le API necessarie.

Avvia Cloud Shell

Eseguirai la maggior parte dei comandi da Google Cloud Shell.

  1. Fai clic su Attiva Cloud Shell nella parte superiore della console Google Cloud.
  2. Verifica l'autenticazione:
    gcloud auth list
    
  3. Conferma il progetto:
    gcloud config get project
    
  4. Se il progetto non è impostato, impostalo utilizzando l'ID progetto:
    gcloud config set project <YOUR_PROJECT_ID>
    

Abilita API

Esegui il seguente comando per attivare le API richieste per BigQuery, Cloud Resource Manager e Vertex AI:

gcloud services enable \
  bigquery.googleapis.com \
  aiplatform.googleapis.com \
  cloudresourcemanager.googleapis.com

Configura l'ambiente e crea il bucket delle dipendenze

  1. Imposta le variabili di ambiente nel terminale:
    export PROJECT_ID=$(gcloud config get project)
    export REGION=us-central1
    export DEPS_BUCKET=$PROJECT_ID-deps-bucket
    
  2. Crea il bucket Cloud Storage delle dipendenze. Gli script PySpark vengono caricati qui al momento dell'invio del job:
    gcloud storage buckets create gs://$DEPS_BUCKET --location=$REGION
    

3. Connettersi al catalogo pubblico di Apache Iceberg

In questo passaggio, ti connetterai a un catalogo Apache Iceberg live di livello di produzione ospitato su BigLake di Google Cloud.

Esegui Spark SQL con la CLI batch Serverless per Apache Spark

Utilizzeremo Google Cloud Serverless per Apache Spark per eseguire job PySpark senza dover gestire l'infrastruttura. Lo configureremo in modo che punti al catalogo REST BigLake pubblico.

  1. Definisci le proprietà del catalogo REST BigLake per evitare di ripeterle.Questa configurazione indica a Spark:
    • Per utilizzare le librerie iceberg-spark-runtime e iceberg-gcp-bundle.
    • Per configurare un catalogo denominato my_catalog utilizzando l'endpoint del catalogo REST BigLake.
    • Per utilizzare Google Cloud Storage (GCS) per leggere i file di dati anziché il file system locale predefinito.
    • Per impostare questo catalogo my_catalog come predefinito per la nostra sessione.
    • Utilizzare le credenziali fornite per una maggiore sicurezza e un accesso ai dati semplificato.
    export METASTORE_PROPERTIES="^|^spark.jars.packages=org.apache.iceberg:iceberg-spark-runtime-3.5_2.12:1.10.0,org.apache.iceberg:iceberg-gcp-bundle:1.10.0|\
    spark.sql.catalog.my_catalog=org.apache.iceberg.spark.SparkCatalog|\
    spark.sql.catalog.my_catalog.type=rest|\
    spark.sql.catalog.my_catalog.uri=https://biglake.googleapis.com/iceberg/v1/restcatalog|\
    spark.sql.catalog.my_catalog.warehouse=gs://biglake-public-nyc-taxi-iceberg|\
    spark.sql.catalog.my_catalog.io-impl=org.apache.iceberg.gcp.gcs.GCSFileIO|\
    spark.sql.catalog.my_catalog.header.x-goog-user-project=$PROJECT_ID|\
    spark.sql.catalog.my_catalog.header.X-Iceberg-Access-Delegation=vended-credentials|\
    spark.sql.catalog.my_catalog.rest.auth.type=org.apache.iceberg.gcp.auth.GoogleAuthManager|\
    spark.sql.defaultCatalog=my_catalog|\
    spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions|\
    spark.log.level=ERROR"
    
  2. Crea un semplice file di query di test:
    cat <<EOF > test.py
    from pyspark.sql import SparkSession
    
    spark = SparkSession.builder.getOrCreate()
    
    spark.sql("SHOW TABLES IN public_data").show()
    EOF
    
  3. Invia il job batch:
    gcloud dataproc batches submit pyspark \
      --project=$PROJECT_ID \
      --region=$REGION \
      --version=2.3 \
      --properties="$METASTORE_PROPERTIES" \
      --deps-bucket=gs://$DEPS_BUCKET \
      test.py
    
    Attendi qualche minuto affinché il job batch venga eseguito.Al termine del job, dovresti visualizzare un output simile al seguente:
    +-----------+----------------+-----------+
    |  namespace|       tableName|isTemporary|
    +-----------+----------------+-----------+
    |public_data|     nyc_taxicab|      false|
    |public_data|nyc_taxicab_2021|      false|
    +-----------+----------------+-----------+
    

4. Eseguire query sui dati Iceberg strutturati

Una volta connesso, hai accesso SQL completo ai set di dati. Eseguiremo una query sul set di dati NYC Taxi modellato come tabella Iceberg.

Eseguire una query di aggregazione standard

Crea un file denominato query.py:

cat <<EOF > query.py
from pyspark.sql import SparkSession

spark = SparkSession.builder.getOrCreate()

query = """
SELECT
  passenger_count,
  COUNT(1) AS num_trips,
  ROUND(AVG(total_amount), 2) AS avg_fare,
  ROUND(AVG(trip_distance), 2) AS avg_distance
FROM public_data.nyc_taxicab
WHERE data_file_year = 2021 AND passenger_count > 0
GROUP BY passenger_count
ORDER BY num_trips DESC
"""

spark.sql(query).show()
EOF

e invialo utilizzando Serverless per Apache Spark:

gcloud dataproc batches submit pyspark \
  --project=$PROJECT_ID \
  --region=$REGION \
  --version=2.3 \
  --properties="$METASTORE_PROPERTIES" \
  --deps-bucket=gs://$DEPS_BUCKET \
  query.py

Attendi qualche minuto per il completamento dell'esecuzione del job batch.

Al termine del job, dovresti vedere un output simile al seguente:

+---------------+---------+--------+------------+
|passenger_count|num_trips|avg_fare|avg_distance|
+---------------+---------+--------+------------+
|              1| 21508009|   18.82|        3.03|
|              2|  4424746|   20.22|        3.40|
|              3|  1164846|   19.84|        3.27|
|              5|   718282|   18.88|        3.07|
|              4|   466485|   20.61|        3.44|
|              6|   452467|   18.97|        3.11|
|              7|       78|   65.24|        3.71|
|              8|       49|   57.39|        5.88|
|              9|       35|   73.26|        6.20|
|             96|        1|   17.00|        2.00|
|            112|        1|   15.00|        2.00|
+---------------+---------+--------+------------+

Perché utilizzare Apache Iceberg qui?

  • Eliminazione delle partizioni: la query filtra in base a data_file_year = 2021. Iceberg consente al motore di saltare completamente la scansione dei dati di altri anni.
  • Agilità del motore: puoi eseguire questa operazione in Spark, Trino o BigQuery senza copiare i dati.

5. Time Travel in Apache Iceberg

Una delle funzionalità più potenti di Iceberg è Time Travel. Ti consente di eseguire query sui dati così come esistevano in una versione o snapshot precedente.

Visualizzare la cronologia della tabella

Crea un file denominato history.py:

cat <<EOF > history.py
from pyspark.sql import SparkSession

spark = SparkSession.builder.getOrCreate()

spark.sql("SELECT * FROM public_data.nyc_taxicab.history").show()
EOF

e invialo:

gcloud dataproc batches submit pyspark \
  --project=$PROJECT_ID \
  --region=$REGION \
  --version=2.3 \
  --properties="$METASTORE_PROPERTIES" \
  --deps-bucket=gs://$DEPS_BUCKET \
  history.py

Nella console dovresti vedere un output simile al seguente:

+--------------------+-------------------+-------------------+-------------------+
|     made_current_at|        snapshot_id|          parent_id|is_current_ancestor|
+--------------------+-------------------+-------------------+-------------------+
|2026-01-07 21:32:...|6333415779680505547|               NULL|               true|
|2026-01-07 21:34:...|1840345522877675925|6333415779680505547|               true|
|2026-01-07 21:36:...|7203554539964460256|1840345522877675925|               true|
|2026-01-07 21:38:...|4573466015237516024|7203554539964460256|               true|
|2026-01-07 21:40:...|3353190952148867790|4573466015237516024|               true|
|2026-01-07 21:42:...|1335547378580631681|3353190952148867790|               true|
|2026-01-07 21:44:...|8203141258229894239|1335547378580631681|               true|
|2026-01-07 21:46:...|1597048231706307813|8203141258229894239|               true|
|2026-01-07 21:48:...|6247811509231462655|1597048231706307813|               true|
|2026-01-07 21:50:...|2527184310045633322|6247811509231462655|               true|
|2026-01-07 21:52:...|2512764101237223642|2527184310045633322|               true|
|2026-01-07 21:52:...|7045957533358062548|2512764101237223642|               true|
|2026-01-07 21:53:...| 531753237516076726|7045957533358062548|               true|
|2026-01-07 21:53:...|4184653573199718274| 531753237516076726|               true|
|2026-01-07 21:54:...|5125223829492177301|4184653573199718274|               true|
|2026-01-07 21:54:...|6844673237417600305|5125223829492177301|               true|
|2026-01-07 21:54:...|6634828203344518093|6844673237417600305|               true|
|2026-01-07 21:55:...|7637728273407236194|6634828203344518093|               true|
|2026-01-07 21:55:...|3424071684958740192|7637728273407236194|               true|
|2026-01-07 21:55:...|1743746294196424254|3424071684958740192|               true|
+--------------------+-------------------+-------------------+-------------------+

Vedrai righe che rappresentano diversi ID snapshot e la data di commit.

Confronta il conteggio delle righe attuale con quello precedente

Crea un file denominato timetravel.py:

cat <<EOF > timetravel.py
from pyspark.sql import SparkSession

spark = SparkSession.builder.getOrCreate()

query = """
SELECT 'Current State' AS version, COUNT(*) AS count FROM public_data.nyc_taxicab
UNION ALL
SELECT 'Past State' AS version, COUNT(*) AS count FROM public_data.nyc_taxicab VERSION AS OF 4573466015237516024
"""

spark.sql(query).show()
EOF

e invialo:

gcloud dataproc batches submit pyspark \
  --project=$PROJECT_ID \
  --region=$REGION \
  --version=2.3 \
  --properties="$METASTORE_PROPERTIES" \
  --deps-bucket=gs://$DEPS_BUCKET \
  timetravel.py

Nella console dovresti vedere un output simile al seguente:

+-------------+----------+
|      version|     count|
+-------------+----------+
|Current State|1293069366|
|   Past State|  72878594|
+-------------+----------+

In questo modo, puoi controllare le modifiche ai dati nel tempo.

6. AI strutturata con BigQuery ML

Ora che hai esplorato i dati Iceberg, utilizziamo le funzionalità di BigQuery AI. Poiché il catalogo Iceberg pubblico è di sola lettura, possiamo utilizzare BigQuery per addestrare un modello nel nostro spazio di lavoro leggendo dalle tabelle pubbliche.

Crea un set di dati locale

Per prima cosa, crea un set di dati nel tuo progetto per archiviare il modello di AI utilizzando la CLI bq:

bq mk --location=$REGION --project_id=$PROJECT_ID iceberg_ai

Addestra un modello di regressione lineare

Ora addestrerai un modello di regressione lineare utilizzando la tabella BigLake Iceberg pubblica.

Crea un file di query e addestra il modello utilizzando bq query:

cat <<'EOF' > train_model.sql
CREATE OR REPLACE MODEL `iceberg_ai.predict_fare`
OPTIONS(model_type='LINEAR_REG', input_label_cols=['fare_amount']) AS
SELECT fare_amount, passenger_count, CAST(trip_distance AS FLOAT64) AS trip_distance
FROM `bigquery-public-data`.`biglake-public-nyc-taxi-iceberg`.public_data.nyc_taxicab
WHERE fare_amount > 0 AND trip_distance > 0 AND RAND() < 0.01; -- Using 1% of data to downsample
EOF

bq query --location=$REGION --use_legacy_sql=false < train_model.sql

Previsione con il modello

Ora che il modello è addestrato, puoi utilizzarlo per prevedere gli importi delle tariffe per i nuovi viaggi utilizzando ML.PREDICT.

Crea un file di query ed esegui la previsione utilizzando bq query:

cat <<'EOF' > predict_fare.sql
SELECT
  predicted_fare_amount, passenger_count, trip_distance
FROM
  ML.PREDICT(MODEL `iceberg_ai.predict_fare`,
    (
    SELECT 2 AS passenger_count, 5.0 AS trip_distance
    )
  );
EOF

bq query --location=$REGION --use_legacy_sql=false < predict_fare.sql

Dovresti vedere un output simile al seguente:

+-----------------------+-----------------+---------------+
| predicted_fare_amount | passenger_count | trip_distance |
+-----------------------+-----------------+---------------+
|     14.12252095150709 |               2 |           5.0 |
+-----------------------+-----------------+---------------+

7. AI non strutturata con BigLake

I dati non sono solo righe e colonne. I data lakehouse unificati gestiscono anche i dati non strutturati (immagini, PDF). Utilizziamo le tabelle di oggetti e i riferimenti agli oggetti per eseguire query sui dati non strutturati.

Le tabelle di oggetti sono tabelle esterne di sola lettura in BigQuery che elencano gli oggetti in un percorso Cloud Storage. Ogni riga rappresenta un file, con colonne per i metadati come uri, size e una colonna speciale ref contenente ObjectRef.

Riferimenti agli oggetti (ObjectRef) puntano ai dati effettivi di un singolo file. Le moderne funzioni BigQuery ML (come AI.GENERATE o AI.AGG) utilizzano ObjectRef per leggere i contenuti dei file (immagini, audio o testo) per l'analisi senza caricare i byte in una tabella standard.

Crea un set di dati per l'AI non strutturata

Innanzitutto, crea un secondo set di dati nel tuo progetto per archiviare le tabelle degli oggetti utilizzando la CLI bq nella multiregione US:

bq mk --location=US --project_id=$PROJECT_ID iceberg_object_ai

Crea una connessione esterna

Per eseguire query sui dati archiviati in Cloud Storage (sia tabelle di oggetti che dati non strutturati) da BigQuery, devi creare una connessione esterna.

Esegui il comando seguente in Cloud Shell per creare una connessione alle risorse Cloud:

bq mk --connection --project_id=$PROJECT_ID --location=US --connection_type=CLOUD_RESOURCE my-conn

Trova l'ID service account creato per la tua connessione:

CONNECTION_SA=$(bq show --format=json --project_id=$PROJECT_ID --connection $PROJECT_ID.us.my-conn | jq -r '.serviceAccountId // .cloudResource.serviceAccountId')

Concedi al service account i ruoli Utente Vertex AI e Visualizzatore oggetti Storage in modo che possa chiamare i modelli Gemini e leggere i dati GCS:

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$CONNECTION_SA" \
  --role="roles/aiplatform.user"

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$CONNECTION_SA" \
  --role="roles/storage.objectViewer"

Creare una tabella degli oggetti

Utilizzeremo la connessione esterna my-conn creata nella sezione precedente per accedere ai dati non strutturati. Crea un file di query e crea la tabella degli oggetti utilizzando bq query:

cat <<'EOF' > create_object_table.sql
CREATE EXTERNAL TABLE `iceberg_object_ai.sample_images`
WITH CONNECTION `us.my-conn`
OPTIONS (
  object_metadata = 'SIMPLE',
  uris = ['gs://cloud-samples-data/vision/landmark/*']
);
EOF

bq query --use_legacy_sql=false < create_object_table.sql

Utilizzare Gemini sui dati degli oggetti

Ora esegui una query utilizzando Gemini per valutare le immagini senza scaricarle.

Esegui query sulle immagini utilizzando SQL standard tramite bq query:

cat <<EOF > query_images.sql
SELECT
  uri,
  image_analysis.description
FROM (
  SELECT
    uri,
    AI.GENERATE(
      (
        'Identify what is happening in the image.',
        ref
      ),
      connection_id => 'us.my-conn',
      endpoint => 'gemini-2.5-flash-lite',
      output_schema => 'event STRING, severity STRING, description STRING'
    ) AS image_analysis
  FROM
    iceberg_object_ai.sample_images
);
EOF

bq query --use_legacy_sql=false < query_images.sql

Esempio di output:

+----------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|                           uri                            |                                                                                                                                                                                                                             description                                                                                                                                                                                                                             |
+----------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| gs://cloud-samples-data/vision/landmark/eiffel_tower.jpg | The Eiffel Tower stands tall against a cloudy sky, overlooking the Seine River in Paris. Boats are docked along the riverbank, and trees line the opposite shore, with bridges and buildings visible in the distance.                                                                                                                                                                                                                                               |
| gs://cloud-samples-data/vision/landmark/pofa.jpg         | A wide shot shows the Palace of Fine Arts, a monumental structure in San Francisco, California. The building features a large rotunda with a dome, surrounded by colonnades. In front of the rotunda is a lagoon. Several people are walking around the grounds. The sky is blue with a few scattered clouds.                                                                                                                                                       |
| gs://cloud-samples-data/vision/landmark/st_basils.jpeg   | A monument stands in front of Saint Basil's Cathedral in Moscow under a bright blue sky with scattered white clouds. The cathedral features distinctive onion domes in various colors and patterns, including red, blue and white stripes, green and beige stripes, and red and blue diamonds. A large green tree partially obscures the left side of the cathedral. People are visible in the foreground near the base of the monument and the cathedral entrance. |
+----------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

Esplorazione diretta di ObjectRef: analisi del sentiment

Mentre le tabelle di oggetti gestiscono automaticamente i riferimenti ai file, puoi interagire direttamente con questi oggetti utilizzando i riferimenti agli oggetti di BigQuery per eseguire analisi al volo su singoli file.

Ad esempio, puoi utilizzare un piccolo file di testo archiviato nel tuo bucket GCS (utilizzando la variabile $DEPS_BUCKET creata in precedenza) e analizzarlo utilizzando OBJ.MAKE_REF con bq query.

Innanzitutto, crea un piccolo file di testo e caricalo nel bucket:

cat <<'EOF' > review.txt
This product is fantastic! It exceeded my expectations. The quality is top-notch. I highly recommend it to everyone!
EOF

gcloud storage cp review.txt gs://${DEPS_BUCKET}/review.txt

Ora esegui una query sul file utilizzando OBJ.MAKE_REF in SQL standard:

cat <<EOF > sentiment_analysis.sql
SELECT
  AI.GENERATE(
    (
      'Analyze the sentiment of this text file. Is it positive, negative, or neutral? Explain why.',
      OBJ.MAKE_REF('gs://${DEPS_BUCKET}/review.txt', 'us.my-conn')
    ),
    connection_id => 'us.my-conn',
    endpoint => 'gemini-2.5-flash-lite'
  ).result AS ml_generate_text_result;
EOF

bq query --use_legacy_sql=false < sentiment_analysis.sql

Esempio di output:

+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|                                                                                 ml_generate_text_result                                                                                  |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| This text file has a **strongly positive** sentiment.                                                                                                                                    |
|                                                                                                                                                                                          |
| Here's why:                                                                                                                                                                              |
|                                                                                                                                                                                          |
| *   **Positive Keywords:** The text is filled with unequivocally positive words and phrases:                                                                                             |
|     *   "fantastic"                                                                                                                                                                      |
|     *   "exceeded my expectations"                                                                                                                                                       |
|     *   "top-notch"                                                                                                                                                                      |
|     *   "highly recommend"                                                                                                                                                               |
|                                                                                                                                                                                          |
| *   **Enthusiastic Language:** The use of exclamation marks ("!") further amplifies the positive tone, indicating excitement and strong approval.                                        |
|                                                                                                                                                                                          |
| *   **Lack of Negative or Neutral Elements:** There are no words, phrases, or implications that suggest any dissatisfaction, criticism, or even indifference.                            |
|                                                                                                                                                                                          |
| In summary, the author's language is enthusiastic and uses multiple strong positive descriptors, leaving no room for doubt that their opinion of the product is overwhelmingly positive. |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

8. Esegui la pulizia

Per evitare addebiti continui al tuo account Google Cloud, elimina le risorse create durante questo codelab.

Elimina set di dati e connessione

Esegui questo comando in Cloud Shell per eliminare i set di dati e la connessione:

bq rm -r -f --location=$REGION iceberg_ai
bq rm -r -f --location=US iceberg_object_ai
bq rm --connection $PROJECT_ID.US.my-conn

Elimina bucket GCS e file locali

Libera spazio nei bucket GCS e nei file locali:

# Delete GCS buckets
PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
gcloud storage rm -r gs://dataproc-temp-${REGION}-${PROJECT_NUMBER}-*
gcloud storage rm -r gs://dataproc-staging-${REGION}-${PROJECT_NUMBER}-*
gcloud storage rm -r gs://${DEPS_BUCKET}

# Delete local files
rm -f train_model.sql predict_fare.sql create_object_table.sql query_images.sql sentiment_analysis.sql test.py query.py history.py timetravel.py review.txt

Se l'hai creato solo per questo lab, puoi anche eliminare l'intero progetto.

9. Complimenti

Complimenti! Hai creato correttamente un Unified Data Lakehouse utilizzando Apache Iceberg, BigLake e BigQuery AI.

Cosa hai imparato

  • Come connettersi ed eseguire query sui cataloghi REST Apache Iceberg pubblici.
  • Utilizzo di Time Travel in Iceberg per controllare le versioni del set di dati.
  • Addestramento di modelli BigQuery ML su dati strutturati.
  • Collegamento di dati non strutturati (immagini) utilizzando tabelle di oggetti e ObjectRef.
  • Utilizzo di Gemini direttamente in BigQuery SQL per analizzare le immagini.

Documenti di riferimento