Créer un graphe de propriétés multicloud sur un lakehouse ouvert et sans limites

Ce tutoriel vous explique comment créer un graphe BigQuery unique qui unifie les silos de données dans deux clouds différents à l'aide d'un lakehouse ouvert et sans limites, et de points de terminaison de catalogue REST Apache Iceberg sans déplacer les données.

Avant de commencer

Avant de commencer, configurez votre environnement et activez les API requises.

  1. Définissez votre projet et votre région, puis activez les API :

    export PROJECT_ID="your-gcp-project-id"
    export REGION="us-east4"
    
    gcloud config set project "$PROJECT_ID"
    
    gcloud services enable \
      biglake.googleapis.com \
      bigquery.googleapis.com \
      secretmanager.googleapis.com \
      storage.googleapis.com
    
  2. Créez un environnement virtuel Python pour le chargeur :

    python3 -m venv iceberg-venv
    source iceberg-venv/bin/activate
    pip install --quiet "pyiceberg[pyarrow]"
    

Créer le Google Cloud spoke

Configurez un catalogue REST Apache Iceberg ouvert, soutenu par un bucket Cloud Storage, et chargez-y trois tables Iceberg.

  1. Créez le bucket et le catalogue :

    export GCS_BUCKET="gs://${PROJECT_ID}-xcloud-lake"
    export GCS_CATALOG="gcs_lake"
    
    gcloud storage buckets create "$GCS_BUCKET" \
      --project="$PROJECT_ID" \
      --location="$REGION"
    
    gcloud biglake iceberg catalogs create "$GCS_CATALOG" \
      --project="$PROJECT_ID" \
      --catalog-type=biglake \
      --primary-location="$REGION" \
      --default-location="$GCS_BUCKET"
    
  2. Enregistrez le script Python suivant sous le nom load_gcs.py pour amorcer les tables :

    import subprocess, pyarrow as pa
    from pyiceberg.catalog.rest import RestCatalog
    from pyiceberg.schema import Schema
    from pyiceberg.types import NestedField, StringType, LongType, DoubleType
    import os
    
    PROJECT = os.environ["PROJECT_ID"]
    CATALOG = os.environ["GCS_CATALOG"]
    TOKEN = subprocess.check_output(
        ["gcloud", "auth", "application-default", "print-access-token"], text=True
    ).strip()
    
    cat = RestCatalog(
        name=CATALOG,
        uri="https://biglake.googleapis.com/iceberg/v1/restcatalog",
        warehouse=f"bl://projects/{PROJECT}/catalogs/{CATALOG}",
        token=TOKEN,
        **{"header.x-goog-user-project": PROJECT,
           "header.X-Iceberg-Access-Delegation": "vended-credentials"},
    )
    
    cat.create_namespace_if_not_exists("retail")
    
    def mk(name, schema, table):
        ident = ("retail", name)
        try: cat.drop_table(ident)
        except Exception: pass
        t = cat.create_table(ident, schema=schema)
        t.append(table)
        print(f"  {name}: {table.num_rows} rows")
    
    # customers
    mk("customers",
       Schema(NestedField(1, "customer_id", StringType()),
              NestedField(2, "name", StringType()),
              NestedField(3, "region", StringType())),
       pa.table({
           "customer_id": ["C1", "C2", "C3", "C4", "C5", "C6"],
           "name": ["Ana", "Ben", "Cara", "Dan", "Eve", "Finn"],
           "region": ["west", "west", "east", "east", "west", "south"],
       }))
    
    # orders
    mk("orders",
       Schema(NestedField(1, "order_id", StringType()),
              NestedField(2, "customer_id", StringType()),
              NestedField(3, "status", StringType()),
              NestedField(4, "amount", DoubleType())),
       pa.table({
           "order_id": ["O1","O2","O3","O4","O5","O6","O7","O8","O9","O10"],
           "customer_id": ["C1","C1","C2","C3","C3","C4","C5","C5","C6","C2"],
           "status": ["shipped"]*8 + ["pending","shipped"],
           "amount": [156.0,89.0,120.0,147.0,89.0,199.0,25.0,88.0,80.0,224.0],
       }))
    
    # order_items
    mk("order_items",
       Schema(NestedField(1, "order_item_id", StringType()),
              NestedField(2, "order_id", StringType()),
              NestedField(3, "product_id", StringType()),
              NestedField(4, "quantity", LongType()),
              NestedField(5, "amount", DoubleType())),
       pa.table({
           "order_item_id": [f"OI{i}" for i in range(1, 16)],
           "order_id":  ["O1","O1","O2","O3","O3","O4","O5","O6","O6","O7","O8","O9","O10","O10","O2"],
           "product_id": ["P1","P2","P3","P1","P5","P4","P3","P6","P8","P7","P1","P2","P4","P5","P6"],
           "quantity":  [1,2,1,1,3,1,1,1,