Logo Google Cloud con Eduardo

Google Cloud con Eduardo

Descarga el código de la lección

Información básica de protección de datos: Responsable: Eduardo Martínez Agrelo. Finalidad: Gestionar y facilitar la descarga del recurso solicitado. Legitimación: Consentimiento del interesado (Art. 6.1.a RGPD). Destinatarios: Proveedor de infraestructura técnica (Google Cloud / Firebase). Derechos: Acceso, rectificación y supresión en eduardomartinezagrelo@gmail.com.
Dataform en GCP BigQuery: Arquitectura ELT, SQLX Incremental y CI/CD Empresarial
✦ Guía Técnica & Arquitectura

Dataform en GCP BigQuery: Arquitectura ELT, SQLX Incremental y CI/CD Empresarial

El paradigma de ingeniería de datos moderno demanda la separación estricta entre almacenamiento, procesamiento y orquestación semántica. En el ecosistema de Google Cloud Platform (GCP), Dataform se consolida como la solución nativa y serverless de orquestación ELT dentro del propio motor analítico de BigQuery. Esta guía técnica detalla la construcción de pipelines escalables bajo arquitectura Medallion, optimización de slots de cómputo y validación de calidad de datos en producción.

Modelado SQLX
Lógica modular con JavaScript reutilizable.
Patrón Incremental
Reducción drástica de costes de escaneo.
Data Assertions
Testing de calidad nativo pre y post-cargue.
CI/CD Multi-Target
Compilation Overrides para Dev/Staging/Prod.
GCP Dataform Google BigQuery SQLX Declarative JavaScript Includes FinOps & Partitioning GCP Cloud Workflows Git Integration

Matriz de Decisión: Transformación ELT en BigQuery

Seleccionar la herramienta de transformación adecuada impacta directamente en los costes operativos, la latencia de ingestión y la sobrecarga de mantenimiento del equipo de ingeniería.

Criterio Técnico GCP Dataform dbt Core (Cloud Composer/K8s) BigQuery Scheduled Queries
Infraestructura Serverless gestionado 100% por GCP Requiere VMs/Pods (Composer, GKE o Runners) Serverless básico
Coste Operativo 0 € coste de servicio (solo cómputo BQ) Coste de computación de VMs + Slots BQ Solo cómputo BQ
Control de Dependencias (DAG) Nativo por resolución de referencias (ref()) Nativo por referencias (Jinja ref()) No soportado (ejecuciones aisladas)
Linaje & Data Governance Linaje visual interactivo en GCP Console dbt Docs o herramientas externas Inexistente
Data Quality Assertions Nativo en SQLX (bloqueante o no bloqueante) Nativo (dbt test / generic tests) Manual mediante scripts SQL adicionales

⚠️ Antipatrón de Producción: Full Table Scan en Modelos Incrementales

Un fallo recurrente al diseñar tablas incrementales con Dataform es omitir el filtrado determinista por partición dentro del bloque pre_operations o en la cláusula where condicional. Si la tabla destino está particionada por DATE(transaction_timestamp) pero la subconsulta incremental lee toda la tabla origen sin un límite explícito de ventana temporal, BigQuery ejecutará un escaneo completo de la tabla origen en cada ejecución.

Mitigación Arquitectónica: Combina siempre la macro when(incremental(), ...) con particionamiento y clustering en el bloque config, fijando una ventana móvil de re-procesamiento (por ejemplo, lookback window de 3 días) para absorber datos tardíos (late-arriving data) sin degradar el presupuesto FinOps.

Implementación Práctica: Modelo Incremental con Calidad de Datos

A continuación se presenta un pipeline de transformación de capa Silver implementado en SQLX. Incluye deduplicación por clave primaria, gestión de marcas temporales, configuración de clustering y aserciones de integridad:

// Archivo: definitions/silver/silver_customer_orders.sqlx
config {
  type: "incremental",
  schema: "silver_layer",
  tags: ["daily_pipeline", "core_silver"],
  uniqueKey: ["order_id"],
  bigquery: {
    partitionBy: "DATE(order_timestamp)",
    clusterBy: ["customer_id", "order_status"]
  },
  assertions: {
    uniqueKey: ["order_id"],
    nonNull: ["order_id", "customer_id", "order_timestamp", "net_amount"],
    rowConditions: [
      'net_amount >= 0'
    ]
  }
}

-- Reutilización de funciones utilitarias JavaScript desde includes/utils.js
js {
  const sanitize = require("includes/utils.js");
}

SELECT
  order_id,
  customer_id,
  ${sanitize.cleanString("order_status")} AS order_status,
  order_timestamp,
  net_amount,
  tax_amount,
  (net_amount + tax_amount) AS total_amount,
  CURRENT_TIMESTAMP() AS ingestion_timestamp
FROM
  ${ref("bronze_raw_orders")}

${when(incremental(), `
  WHERE order_timestamp >= (
    SELECT 
      -- Ventana de seguridad de 3 días para late-arriving events
      TIMESTAMP_SUB(MAX(order_timestamp), INTERVAL 3 DAY) 
    FROM 
      ${self()}
  )
`)}

Módulo de utilidades compartido en JavaScript (includes/utils.js) para estandarización de columnas:

// Archivo: includes/utils.js
function cleanString(columnName) {
  return `TRIM(LOWER(${columnName}))`;
}

function hashKey(columns) {
  return `TO_HEX(MD5(CONCAT(${columns.map(col => `IFNULL(CAST(${col} AS STRING), '')`).join(", '||', ")})))`;
}

module.exports = {
  cleanString,
  hashKey
};

Patrones de Diseño y Multi-Environment CI/CD

En arquitecturas de producción sobre Google Cloud, el código de Dataform no debe contener nombres de proyectos ni datasets en hardcode. El flujo de trabajo enterprise se sustenta en:

  • Arquitectura Medallion en Datasets: Separación física en datasets bronze_raw (ingesta CDC/Event), silver_curated (limpieza, deduplicación y tipado) y gold_analytical (modelos dimensionales y métricas de negocio).
  • Compilation Overrides: Configuración de Release Configurations asociadas a ramas Git (main, staging, dev) que inyectan de forma dinámica el defaultProject y schemaSuffix (ej. _dev o _stg).
  • Service Accounts con Mínimo Privilegio: La Service Account de ejecución de Dataform debe poseer exclusivamente roles como roles/bigquery.dataEditor en los datasets destino y roles/bigquery.jobUser a nivel de proyecto.

Checklist de Implementación en GCP

  1. Vincular Repositorio Git: Conectar el repositorio de Dataform con Cloud Source Repositories, GitHub Enterprise o GitLab mediante Secret Manager.
  2. Configurar workflow_settings.yaml: Definir la versión de Dataform Core (@dataform/core: 3.x.x) y el dataset por defecto para aserciones de calidad.
  3. Definir Declaraciones de Origen (Sources): Registrar las tablas ingestadas por Cloud Storage o Datastream usando declare({ schema, name }).
  4. Parametrizar Release & Workflow Configurations: Programar invocaciones serverless mediante triggers horarios o eventos en Cloud Pub/Sub integrados con Cloud Composer/Workflows.

Preguntas Frecuentes (FAQ)

¿Cómo maneja Dataform los entornos dev, staging y prod sin duplicar código SQLX?

Dataform utiliza Compilation Overrides dentro de sus configuraciones de release. Esto permite inyectar variables de entorno en tiempo de compilación para modificar el sufijo del dataset o el ID del proyecto de GCP sin alterar una sola línea de código fuente SQLX.

¿Cuál es la diferencia de coste y mantenimiento entre Dataform y dbt Core en Cloud Composer?

Dataform es 100% serverless, prescindiendo del aprovisionamiento, parcheo y pago de infraestructura subyacente (VMs de GKE o Cloud Composer). dbt Core requiere administrar un orquestador, mientras que Dataform sólo genera facturación por las consultas SQL ejecutadas directamente en BigQuery.

¿Cómo previene Dataform la inserción de registros duplicados en cargas incrementales?

Al declarar la directiva uniqueKey: ["primary_column"] en el bloque de configuración, Dataform compila internamente una sentencia MERGE optimizada en lugar de un INSERT directo, actualizando los registros modificados e insertando los nuevos registros de forma atómica.

Sobre el Autor: Eduardo Martínez Agrelo

AI & Data Architect

Especialista en el diseño e implementación de arquitecturas de datos modernas, analítica a escala empresarial y sistemas avanzados de Inteligencia Artificial en entornos multicloud. Centrado en la optimización del rendimiento, gobernanza y eficiencia de costes (FinOps) en plataformas analíticas sobre Google Cloud y BigQuery.