Création d'un module de socle de données
Bien que Cortex Framework fournisse des modules de socle de données prêts à l'emploi pour les systèmes ERP d'entreprise tels que SAP (cortex.sap), vous pouvez également créer de nouveaux modules de socle de données personnalisés dans un espace de noms personnalisé. Cela vous permet de définir des comportements de compilation personnalisés et d'étendre la compatibilité à un nouveau système source. Il peut s'agir de systèmes de gestion de bases de données tels que PostgreSQL, MySQL, etc., qui répliquent leurs données brutes dans BigQuery.
Ce guide vous présente un exemple complet de création d'un module de socle de données pour un système de gestion des tickets du service client dont les données (tables customers, tickets, ticketlogitem) ont été répliquées d'une base de données PostgreSQL dans un ensemble de données BigQuery brut nommé ticketing_data_raw.
Lorsque vous créez un module de socle de données personnalisé, nous vous recommandons d'utiliser un espace de noms personnalisé dédié pour améliorer la gestion du cycle de vie en séparant les extensions et les personnalisations des artefacts Cortex Framework.
Présentation de l'exemple de scénario
Dans ce tutoriel, nous allons :
- créer un espace de noms personnalisé dédié
ticketingpour isoler les actifs du socle de données ; - définir un nouveau module de socle de données de chemin
ticketing.ticketing.foundations.ticketing_system; - configurer les paramètres de table (
table_settings.default.yaml) pour les tablescustomers,ticketsetticketlogitem; - créer des annotations de métadonnées au niveau des colonnes et des champs pour chaque table ;
- enregistrer la source de données brutes (
ticketing_data_raw), l'ensemble de données conforme cible (data_foundation_ticketing) et le nouveau module de socle dansconfig/config.yaml.
Structure des dossiers et des fichiers du module
Tous les fichiers physiques de votre nouveau module de socle de données se trouvent dans votre espace de noms personnalisé sous src/data_modules/. Le tableau et l'arborescence de répertoires suivants indiquent où placer chaque fichier :
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
Important : Avant de commencer, assurez-vous que les tables sources que vous prévoyez de traiter existent dans l'ensemble de données de la couche brute.
| Chemin d'accès au fichier ou au répertoire | Objectif et description |
|---|---|
config/config.yaml |
Enregistre l'espace de noms ticketing, la source de données brutes PostgreSQL, l'ensemble de données BigQuery cible et l'instance du module de socle. |
src/data_modules/ticketing/ticketing/foundations/ticketing_system/manifest.yaml |
Déclare les métadonnées du module, le nom à afficher, la catégorie (par exemple, foundation), le type de module (par exemple, generic) et la classe de compilateur de générateur utilisée lors de la compilation. |
src/data_modules/ticketing/ticketing/foundations/ticketing_system/table_settings.default.yaml |
Configure les tables sources de ticketing_data_raw qui doivent être conformes, ainsi que les dataformTags d'optimisation BigQuery, les bigQueryLabels, les détails de partition et les détails de cluster. |
src/data_modules/ticketing/ticketing/foundations/ticketing_system/annotations/*.yaml |
Contient des métadonnées YAML enrichies décrivant les définitions de table et de champ. Elles sont automatiquement fusionnées dans les définitions Dataform compilées afin que les descriptions soient conservées dans les métadonnées de la table BigQuery. |
src/data_modules/ticketing/ticketing/foundations/ticketing_system/builder.py |
Facultatif. Si votre base de données source nécessite un nettoyage de données personnalisé ou des transformations SQL spécifiques à un dialecte lors de la compilation, vous pouvez définir une classe de compilateur au niveau du module ici. |
Étape 1 : Enregistrez l'espace de noms, la source de données et la cible dans config.yaml
Avant de créer les fichiers physiques, ouvrez votre fichier de configuration de déploiement (config/config.yaml) et déclarez l'espace de noms personnalisé, l'ensemble de données source PostgreSQL brut et l'ensemble de données de destination dans lequel les tables conformes seront créées :
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
Étape 2 : Enregistrez le module de socle de données dans config.yaml
Dans la section data.modules.foundations de config/config.yaml, enregistrez la nouvelle instance du module de socle de données, en liant la source de données (ticketing_data_raw) à la cible de données (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"
Étape 3 : Créez le fichier manifeste du module
Créez le fichier manifeste déclarant les métadonnées de votre module : 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
Étape 4 : Créez le fichier de paramètres de table (table_settings.default.yaml)
Créez le fichier de configuration de table par défaut src/data_modules/ticketing/ticketing/foundations/ticketing_system/table_settings.default.yaml. Ce fichier définit comment les tables PostgreSQL répliquées (customers, tickets, ticketlogitem) sont matérialisées, partitionnées et mises en cluster dans 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]
Étape 5 : Créez des annotations de métadonnées au niveau des champs
Pour vous assurer que vos tables conformes contiennent une documentation claire dans BigQuery, créez un fichier YAML d'annotation pour chaque table dans src/data_modules/ticketing/ticketing/foundations/ticketing_system/annotations/. Le nom de fichier doit correspondre exactement au nom de la table source.
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"
Étape 6 : (Facultatif) Définissez un compilateur de socle personnalisé
Si votre socle de données PostgreSQL nécessite une logique lors de la compilation (telle que la conversion automatique de types de données, la conversion d'horodatages ou des règles de nettoyage des données dans toutes les tables), vous pouvez définir un compilateur personnalisé limité à ce module.
Créez 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)
Validation du nouveau module de socle
Pour valider et déployer le module de socle de données que vous venez de créer :
- Exécutez le script de compilation et de déploiement de Cortex Framework :
bash uv run cortex-build-and-deploy --config "config/config.yaml" - Vérifiez que la compilation Dataform a réussi sans erreur et que des scripts
.sqlxont été générés pourcustomers,ticketsetticketlogitem. - Suivez les étapes de post-déploiement pour exécuter les actions de votre pipeline Dataform et vérifier les enregistrements conformes dans votre ensemble de données
data_foundation_ticketingdans BigQuery.
Pour vérifier que le module de socle de données personnalisé est compilé et déployé correctement, consultez la section Validation de la page Extensibilité des produits de données.
- Étape précédente : Configurer un espace de noms personnalisé
- Étape suivante : Créer un module de produit de données
- Retour à la présentation