Creazione del modulo della base dati

Sebbene Cortex Framework fornisca moduli della base dati predefiniti per i sistemi ERP aziendali come SAP (cortex.sap), puoi anche creare nuovi moduli della base dati personalizzati all'interno di uno spazio dei nomi personalizzato. In questo modo puoi definire comportamenti di compilazione personalizzati ed estendere il supporto a un nuovo sistema di origine. Questi possono includere sistemi di gestione di database come PostgreSQL, MySQL e così via che replicano i dati non elaborati in BigQuery.

Questa guida illustra un esempio end-to-end di creazione di un nuovo modulo della base dati per un sistema di gestione dei ticket di assistenza clienti i cui dati (tabelle customers, tickets, ticketlogitem) sono stati replicati da un database PostgreSQL in un set di dati BigQuery non elaborato denominato ticketing_data_raw.

Quando crei un modulo della base dati personalizzato, ti consigliamo di utilizzare uno spazio dei nomi personalizzato dedicato per migliorare la gestione del ciclo di vita separando le estensioni e le personalizzazioni dagli artefatti di Cortex Framework.

Panoramica dello scenario di esempio

In questa procedura dettagliata:

  1. Creeremo uno spazio dei nomi personalizzato dedicato ticketing per isolare gli asset della base dati.
  2. Definiremo un nuovo modulo della base dati con il percorso ticketing.ticketing.foundations.ticketing_system.
  3. Configureremo le impostazioni della tabella (table_settings.default.yaml) per le tabelle customers, tickets e ticketlogitem.
  4. Creeremo annotazioni di metadati a livello di colonna e campo per ogni tabella.
  5. Registreremo l'origine dati non elaborata (ticketing_data_raw), il set di dati di destinazione conforme (data_foundation_ticketing) e il nuovo modulo della base in config/config.yaml.

Struttura di cartelle e file del modulo

Tutti i file fisici del nuovo modulo della base dati si trovano all'interno dello spazio dei nomi personalizzato in src/data_modules/. La tabella e la struttura di directory seguenti descrivono dove inserire ogni file:

config/
└── config.yaml                                           # Global configuration & module registration
src/data_modules/ticketing/ticketing/foundations/ticketing_system/
├── manifest.yaml                                         # Declares module category, type, and builder
├── table_settings.default.yaml                           # Table materialization, bigQueryLabels, dataformTags, and layouts
├── builder.py                                            # (Optional) Custom Dataform generator class for this module
└── annotations/                                          # Field and column-level schema descriptions
    ├── customers.yaml
    ├── tickets.yaml
    └── ticketlogitem.yaml

Importante: prima di iniziare, assicurati che le tabelle di origine che prevedi di elaborare esistano nel set di dati del livello non elaborato.

Percorso del file o della directory Scopo e descrizione
config/config.yaml Registra lo spazio dei nomi ticketing, l'origine dati non elaborata PostgreSQL, il set di dati BigQuery di destinazione e l'istanza del modulo della base.
src/data_modules/ticketing/ticketing/foundations/ticketing_system/manifest.yaml Dichiara i metadati del modulo, il nome visualizzato, la categoria (ad es. foundation), il tipo di modulo (ad es. generic) e la classe del generatore utilizzata durante la compilazione.
src/data_modules/ticketing/ticketing/foundations/ticketing_system/table_settings.default.yaml Configura le tabelle di origine di ticketing_data_raw che devono essere conformi, insieme a dataformTags, bigQueryLabels, dettagli della partizione e dettagli del cluster di ottimizzazione di BigQuery.
src/data_modules/ticketing/ticketing/foundations/ticketing_system/annotations/*.yaml Contiene metadati YAML avanzati che descrivono le definizioni di tabelle e campi. Questi vengono uniti automaticamente nelle definizioni Dataform compilate, in modo che le descrizioni persistano nei metadati della tabella BigQuery.
src/data_modules/ticketing/ticketing/foundations/ticketing_system/builder.py Facoltativo. Se il database di origine richiede la pulizia dei dati personalizzata o trasformazioni SQL specifiche del dialetto durante la compilazione, puoi definire una classe di compilazione a livello di modulo qui.

Passaggio 1: registra lo spazio dei nomi, l'origine dati e la destinazione in config.yaml

Prima di creare i file fisici, apri il file di configurazione del deployment (config/config.yaml) e dichiara lo spazio dei nomi personalizzato, il set di dati di origine PostgreSQL non elaborato e il set di dati di destinazione in cui verranno create le tabelle conformi:

data:
  namespaces:
    - name: cortex
      path: ../src/data_modules/cortex
    - name: ticketing                              # <-- Name of custom namespace
      path: ../src/data_modules/ticketing          # <-- Points to subdirectory under 'src/data_modules/'

  datasets:
    - id: ticketing_data_raw                       # <-- Unique source ID
      projectId: "source_project_id"
      datasetId: ticketing_data_raw                # <-- Raw dataset containing PostgreSQL replication tables
    - id: data_foundation_ticketing                # <-- Unique target ID
      projectId: "target_project_id"
      datasetId: data_foundation_ticketing         # <-- Target dataset for conformed foundation tables

Passaggio 2: registra il modulo della base dati in config.yaml

Nella sezione data.modules.foundations di config/config.yaml, registra la nuova istanza del modulo della base dati, collegando l'origine dati (ticketing_data_raw) alla destinazione dati (data_foundation_ticketing):

data:
  modules:
    foundations:
      - moduleId: ticketing_foundation
        modulePath: ticketing.ticketing.foundations.ticketing_system   # Format: {namespace}.{systemtype}.{module_type:foundations}.{subsystemtype}
        dataSourceId: ticketing_data_raw
        dataTargetId: data_foundation_ticketing
        # Custom table settings file relative to 'config/' directory
        # Recommended path: '{namespace_dir}/{system_type}/foundations/{system_sub_type}/table_settings.yaml'
        # If omitted, defaults to "../src/data_modules/ticketing/ticketing/foundations/ticketing_system/table_settings.default.yaml"
        tableSettings: "ticketing/ticketing/foundations/ticketing_system/table_settings.yaml"

Passaggio 3: crea il file manifest del modulo

Crea il file manifest che dichiara i metadati del modulo: src/data_modules/ticketing/ticketing/foundations/ticketing_system/manifest.yaml.

displayName: Ticketing System Data Foundation
description: Conformed foundation tables for PostgreSQL raw ticketing database.
category: foundation
type: generic
builder: ticketing_foundation

Passaggio 4: crea il file delle impostazioni della tabella (table_settings.default.yaml)

Crea il file di configurazione della tabella predefinita src/data_modules/ticketing/ticketing/foundations/ticketing_system/table_settings.default.yaml. Questo file definisce come le tabelle PostgreSQL replicate (customers, tickets, ticketlogitem) vengono materializzate, partizionate e raggruppate in cluster in BigQuery:

common:
  - source:
      tableName: customers
    target:
      bigQueryLabels:
        - key: data_class
          value: master
      dataformTags: [ticketing, foundation, masterdata]
      clusterDetails:
        columns: [customer_id]

  - source:
      tableName: tickets
    target:
      bigQueryLabels:
        - key: data_class
          value: transactional
      dataformTags: [ticketing, foundation, transactional]
      partitionDetails:
        column: created_at
        partitionType: time
        timeGrain: day
      clusterDetails:
        columns: [ticket_id, customer_id]

  - source:
      tableName: ticketlogitem
    target:
      bigQueryLabels:
        - key: data_class
          value: transactional
      dataformTags: [ticketing, foundation, transactional]
      partitionDetails:
        column: log_timestamp
        partitionType: time
        timeGrain: day
      clusterDetails:
        columns: [ticket_id, log_id]

Passaggio 5: crea annotazioni di metadati a livello di campo

Per assicurarti che le tabelle conformi contengano una documentazione chiara in BigQuery, crea un file YAML di annotazione per ogni tabella all'interno di src/data_modules/ticketing/ticketing/foundations/ticketing_system/annotations/. Il nome file deve corrispondere esattamente al nome della tabella di origine.

annotations/customers.yaml

description: "Customer master data conformed from PostgreSQL raw ticketing database."
fields:
  - name: "customer_id"
    description: "Unique customer identifier, PK"
  - name: "email"
    description: "Primary email address associated with the customer"
  - name: "full_name"
    description: "Customer full name or account contact name"
  - name: "created_at"
    description: "Timestamp when the customer record was originally created in PostgreSQL"

annotations/tickets.yaml

description: "Customer service tickets conformed from PostgreSQL raw ticketing database."
fields:
  - name: "ticket_id"
    description: "Unique ticket identifier, PK"
  - name: "customer_id"
    description: "Foreign key referencing customers.customer_id"
  - name: "subject"
    description: "Summary or subject line of the customer inquiry"
  - name: "status"
    description: "Current ticket lifecycle status (e.g., OPEN, IN_PROGRESS, RESOLVED, CLOSED)"
  - name: "priority"
    description: "Priority severity level (e.g., LOW, MEDIUM, HIGH, URGENT)"
  - name: "created_at"
    description: "Timestamp when the ticket was created"
  - name: "updated_at"
    description: "Timestamp when the ticket was last modified"

annotations/ticketlogitem.yaml

description: "Audit log history and activity events for customer service tickets."
fields:
  - name: "log_id"
    description: "Unique log event identifier, PK"
  - name: "ticket_id"
    description: "Foreign key referencing tickets.ticket_id"
  - name: "action"
    description: "Action or event performed on the ticket"
  - name: "description"
    description: "Notes and description on performed events on the ticket"
  - name: "performed_by"
    description: "User, agent, or automated system that performed the action"
  - name: "log_timestamp"
    description: "Exact timestamp when the activity log event occurred"

Passaggio 6: (facoltativo) definisci un generatore della base personalizzato

Se la base dati PostgreSQL richiede una logica durante la compilazione (ad esempio regole di conversione automatica del tipo di dati, conversione del timestamp o pulizia dei dati in tutte le tabelle), puoi definire un generatore personalizzato con ambito limitato a questo modulo.

Crea src/data_modules/ticketing/ticketing/foundations/ticketing_system/builder.py:

import logging
import pathlib
import yaml
from common.builders.base import FoundationBuilder, Source
from common.registry import builder_registry
from common.schemas import config_schema, manifest_schema

logger = logging.getLogger(__name__)

@builder_registry.register("ticketing_foundation")
class TicketingFoundationBuilder(FoundationBuilder[config_schema.BaseModuleConfig]):
    """Custom Dataform generator for PostgreSQL ticketing data foundation."""

    def build(
        self,
        *,
        module_id: str,
        module_config: config_schema.BaseModuleConfig,
        global_config: config_schema.GlobalConfig,
        manifest: manifest_schema.ManifestConfig,
        base_dir: pathlib.Path,
        annotations_dir: pathlib.Path,
        output_dir: pathlib.Path,
        module_dir_name: str,
        sources_registry: set[Source],
        table_settings_file: pathlib.Path | None = None,
        required_tables: set[str] | None = None,
    ) -> None:
        logger.info("Building ticketing data foundation for module: %s", module_id)
        
        # 1. Load table settings
        if not table_settings_file or not table_settings_file.exists():
            logger.warning("No valid table settings found for %s", module_id)
            return

        with open(table_settings_file, encoding="utf-8") as f:
            settings = yaml.safe_load(f) or {}

        tables = settings.get("common", [])
        source_config = global_config.get_data_source(module_config.data_source_id)
        target_dataset = global_config.get_data_target(module_config.data_target_id)

        # 2. Generate Dataform .sqlx files for each table
        for table_item in tables:
            source_table = table_item["source"]["tableName"]
            if required_tables and source_table not in required_tables and not table_item.get("deployAlways"):
                continue

            # Register source table for centralized source generation
            sources_registry.add(Source(source_config.project_id, source_config.dataset_id, source_table))

            # Retrieve labels if configured
            bigquery_config = {}
            if "bigQueryLabels" in table_item["target"]:
                labels_dict = {label["key"]: label["value"] for label in table_item["target"]["bigQueryLabels"]}
                bigquery_config["labels"] = labels_dict

            dataform_tags = table_item["target"].get("dataformTags", ["ticketing", "foundation"])

            sqlx_content = f"""config {{
  type: "table",
  schema: "{target_dataset.dataset_id}",
  name: "{source_table}",
  tags: {dataform_tags}"""
            
            if bigquery_config:
                sqlx_content += f",\n  bigquery: {bigquery_config}"
                
            sqlx_content += f"""
}}

SELECT *
FROM `${{source_config.project_id}}.${{source_config.dataset_id}}.{source_table}`
"""
            out_file = output_dir / f"{source_table}.sqlx"
            out_file.write_text(sqlx_content, encoding="utf-8")
            logger.info("Generated %s", out_file)

Verifica del nuovo modulo della base

Per verificare ed eseguire il deployment del modulo della base dati appena creato:

  1. Esegui lo script di compilazione ed esecuzione del deployment di Cortex Framework: bash uv run cortex-build-and-deploy --config "config/config.yaml"
  2. Verifica che la compilazione di Dataform sia riuscita senza errori e che siano stati generati script .sqlx per customers, tickets e ticketlogitem.
  3. Segui i passaggi successivi al deployment per eseguire le azioni della pipeline Dataform e verificare i record conformi all'interno del set di dati data_foundation_ticketing in BigQuery.

Per verificare che il modulo della base dati personalizzato venga compilato ed eseguito il deployment correttamente, consulta la sezione Verifica nella pagina Estensibilità del prodotto dati.