Módulo 2: The Star Schema And Conformed Dimensions
El bus matrix: mapeando los procesos de Kiosko
Descripción
La lección anterior comparó dos procesos a la vez —orders y sessions— y encontró que dim_store y dim_date son conformadas entre ambos. Esta lección generaliza esa comparación en una sola herramienta: el bus matrix, una tabla con los procesos de negocio en las filas y las dimensiones en las columnas, marcando con una X cada combinación que existe. Es, literalmente, el mapa completo de un warehouse dimensional, y —esto es lo importante— se construye antes de escribir el SQL de cada tabla nueva, no después.
Conexión con el módulo. Esta lección no ejecuta ningún JOIN sobre datos reales —el bus matrix es un artefacto de planeación, no una consulta—. Lo que produce es el mapa que la lección 7 va a confirmar con código: qué dimensiones necesita fact_orders para su ensamblaje final.
Una analogía: el mapa de rutas de autobús
El nombre "bus matrix" no es una metáfora vaga — Kimball lo tomó, con toda intención, del sistema eléctrico de un edificio o una computadora: un bus es una línea compartida por la que viaja información o energía, accesible desde varios puntos sin necesitar una conexión dedicada para cada uno. La analogía cotidiana es más simple todavía: piensa en el mapa de rutas de autobús de una ciudad. Ese mapa no dice "cómo llegar de A a B" para un viaje específico — dice, de un vistazo, qué ruta pasa por qué estación. Una persona que quiere planear cualquier viaje futuro, sin saber todavía cuál va a hacer, puede mirar el mapa y ver que la Ruta 5 pasa por las estaciones Centro, Norte y Terminal, mientras que la Ruta 12 solo pasa por Centro y Sur.
El bus matrix de un warehouse es exactamente ese mapa, con procesos de negocio en vez de rutas y dimensiones en vez de estaciones: te dice, de un vistazo y antes de construir nada, qué dimensión (estación) sirve a qué proceso (ruta). Un equipo de datos que dibuja este mapa antes de escribir la primera línea de SQL de un proceso nuevo evita, sistemáticamente, el error que la lección anterior nombró: crear una dimensión duplicada porque nadie se detuvo a preguntar "¿esto ya existe en otro lado del mapa?".
Ejemplo trabajado: el bus matrix de Kiosko, hoy y lo que viene
El bus matrix se representa aquí como una estructura de datos fija en Python —no como una consulta SQL, porque no describe datos, describe decisiones de diseño— y se imprime como una tabla de texto.
# bus_matrix.py
# El bus matrix de Kiosko: filas = procesos de negocio, columnas = dimensiones.
# No es un JOIN, no es SQL ejecutado sobre datos -- es una tabla de planeacion,
# el mismo tipo de artefacto que Kimball describe para mapear TODO un warehouse
# antes de construir cada pieza. Se representa aqui como una estructura de datos
# fija en Python, deterministica, y se imprime como tabla.
BUS_MATRIX = [
# (business_process, fact_table, status, {dim_store, dim_product, dim_date})
("orders", "fact_orders", "construido (M1-M2)", {"dim_store", "dim_product", "dim_date"}),
("sessions", "fact_sessions", "planeado (M6)", {"dim_store", "dim_date"}),
("store_activity", "fact_store_activity", "planeado (M6)", {"dim_store", "dim_date"}),
]
DIMENSIONS = ["dim_store", "dim_product", "dim_date"]
header = f"{'business_process':16} | {'fact_table':20} | " + " | ".join(f"{d:11}" for d in DIMENSIONS) + " | status"
print(header)
print("-" * len(header))
for process, fact_table, status, dims in BUS_MATRIX:
marks = " | ".join(f"{'X':11}" if d in dims else f"{'.':11}" for d in DIMENSIONS)
print(f"{process:16} | {fact_table:20} | {marks} | {status}")
print()
for dimension in DIMENSIONS:
processes_using_it = [process for process, _, _, dims in BUS_MATRIX if dimension in dims]
conformed = len(processes_using_it) > 1
label = "CONFORMADA" if conformed else "especifica de un proceso"
print(f"{dimension:12} -> usada por {processes_using_it} [{label}]")
Qué esperar. Al correr python3 bus_matrix.py, la salida es exactamente esta:
business_process | fact_table | dim_store | dim_product | dim_date | status
------------------------------------------------------------------------------------------
orders | fact_orders | X | X | X | construido (M1-M2)
sessions | fact_sessions | X | . | X | planeado (M6)
store_activity | fact_store_activity | X | . | X | planeado (M6)
dim_store -> usada por ['orders', 'sessions', 'store_activity'] [CONFORMADA]
dim_product -> usada por ['orders'] [especifica de un proceso]
dim_date -> usada por ['orders', 'sessions', 'store_activity'] [CONFORMADA]
Este mapa dice, de un vistazo, algo que sería mucho más difícil de ver leyendo el código de tres tablas de hechos por separado: dim_store y dim_date son las dos "rutas de autobús que pasan por todas las estaciones" — cada proceso de negocio de Kiosko, presente y planeado, las necesita—, mientras que dim_product todavía es una "ruta especial", que solo sirve al proceso de ventas. Fíjate en que este mapa incluye dos procesos que todavía no existen (sessions y store_activity, marcados "planeado (M6)") — y esa es, precisamente, la utilidad real del bus matrix: se construye pensando en el warehouse completo, no solo en lo que ya está construido.
Diagrama: el mismo mapa, como grafo bipartito
flowchart LR
subgraph Procesos["Procesos de negocio (filas)"]
P1["orders\nconstruido"]
P2["sessions\nplaneado M6"]
P3["store_activity\nplaneado M6"]
end
subgraph Dims["Dimensiones (columnas)"]
D1["dim_store"]
D2["dim_product"]
D3["dim_date"]
end
P1 --> D1
P1 --> D2
P1 --> D3
P2 --> D1
P2 --> D3
P3 --> D1
P3 --> D3
Profundización: el bus matrix es una herramienta de planeación de equipo, no solo de código
Vale la pena ser explícito sobre algo: en un equipo de datos real, el bus matrix casi nunca lo construye una sola persona mirando código — se dibuja en una sesión de trabajo conjunta, con analistas de negocio, antes de que exista una sola tabla, precisamente para decidir qué construir primero y en qué orden. Kimball recomienda construir el bus matrix completo del warehouse —con todos los procesos de negocio conocidos, aunque algunos se implementen mucho después— como uno de los primeros pasos de cualquier proyecto de modelado dimensional serio, no como una ocurrencia tardía.
Esto explica una decisión del ejemplo trabajado que podría parecer extraña a primera vista: ¿por qué incluir sessions y store_activity, si todavía no existen? Porque el valor del mapa está, precisamente, en anticipar la reutilización antes de construir. Si el equipo de Kiosko hubiera construido fact_orders sin pensar nunca en sessions, es perfectamente posible que, al llegar al módulo 6, alguien hubiera creado una dim_store nueva desde cero para ese proceso —el error exacto que la lección anterior advirtió—, simplemente por no haber consultado un mapa que ya existía. El bus matrix, construido con anticipación, previene ese error estructuralmente, no por disciplina individual de cada persona que construye una tabla nueva.
Una nota sobre el alcance de esta guía: el bus matrix completo de un warehouse de producción real puede tener docenas de procesos y decenas de dimensiones —los ejemplos que aparecen en The Data Warehouse Toolkit de Kimball, para una cadena de retail real, fácilmente superan quince procesos—. El de Kiosko, con tres procesos y tres dimensiones, es intencionalmente pequeño: el objetivo de esta guía no es simular la escala de un warehouse de producción, sino que entiendas la forma de la herramienta con un caso que puedas verificar de memoria, línea por línea.
Errores comunes
Construir el bus matrix solo con los procesos que ya existen. Qué pasa: alguien arma el mapa únicamente con orders, porque es el único proceso que hoy tiene una tabla de hechos real, y no incluye sessions ni store_activity porque "todavía no existen". Por qué pasa: se siente más "honesto" documentar solo lo que ya está construido, en vez de algo que todavía es un plan. Cómo detectarlo: si tu bus matrix cambia cada vez que se construye un proceso nuevo, en vez de simplemente actualizar una fila que ya estaba prevista, el mapa no cumplió su función de anticipación. Cómo corregirlo: el bus matrix se construye con la visión completa del warehouse, marcando explícitamente qué está construido y qué está planeado (como hace la columna status de esta lección) — el objetivo es anticipar la reutilización de dimensiones, no documentar retroactivamente lo que ya existe.
Confundir "el bus matrix está completo" con "todas las dimensiones deben servir a todos los procesos". Qué pasa: alguien, al ver que dim_product solo tiene una X en el mapa, siente que el diseño está "incompleto" o "desbalanceado", y busca una forma de forzar que dim_product también sirva a sessions o store_activity. Por qué pasa: un mapa con más X se siente, visualmente, más "aprovechado". Cómo detectarlo: si estás inventando una razón artificial para que un proceso use una dimensión que su grano real no necesita, el problema no es el bus matrix — es que estás optimizando la apariencia del mapa en vez del modelo real del negocio. Cómo corregirlo: un bus matrix "desbalanceado" —con algunas dimensiones muy conformadas y otras específicas de un solo proceso— es completamente normal y esperado. dim_date casi siempre termina siendo la dimensión más conformada de cualquier warehouse, precisamente porque casi todo proceso de negocio ocurre en el tiempo; eso no significa que las demás dimensiones estén mal diseñadas.
Tratar el bus matrix como un documento que se escribe una vez y nunca se actualiza. Qué pasa: un equipo dibuja el bus matrix al inicio de un proyecto, lo guarda, y nunca vuelve a consultarlo ni actualizarlo a medida que el warehouse crece con procesos nuevos que nadie anticipó originalmente. Por qué pasa: una vez que el mapa cumplió su propósito inicial, se siente "terminado", como cualquier documento de diseño. Cómo detectarlo: si un proceso de negocio nuevo se construyó sin que nadie revisara primero si alguna dimensión existente ya lo cubría, el bus matrix dejó de usarse como herramienta activa. Cómo corregirlo: el bus matrix es un documento vivo — cada vez que un proceso nuevo entra al warehouse (como sessions y store_activity van a entrar en el módulo 6 de esta guía), la primera pregunta antes de escribir cualquier CREATE TABLE debería ser "¿qué dice el bus matrix sobre las dimensiones que este proceso necesita?".
Ejercicios
Ejercicio 1 — Agrega un cuarto proceso hipotético al bus matrix. Imagina que Kiosko decide, en el futuro, medir "devoluciones de producto" como un proceso de negocio nuevo (fact_returns), que necesitaría dim_store, dim_product y dim_date —las tres dimensiones—. Agrégalo a BUS_MATRIX y vuelve a imprimir el mapa completo.
Ver solución
BUS_MATRIX.append(
("returns", "fact_returns", "hipotetico (fuera de esta guia)", {"dim_store", "dim_product", "dim_date"})
)
header = f"{'business_process':16} | {'fact_table':20} | " + " | ".join(f"{d:11}" for d in DIMENSIONS) + " | status"
print(header)
print("-" * len(header))
for process, fact_table, status, dims in BUS_MATRIX:
marks = " | ".join(f"{'X':11}" if d in dims else f"{'.':11}" for d in DIMENSIONS)
print(f"{process:16} | {fact_table:20} | {marks} | {status}")
Salida esperada:
business_process | fact_table | dim_store | dim_product | dim_date | status
------------------------------------------------------------------------------------------
orders | fact_orders | X | X | X | construido (M1-M2)
sessions | fact_sessions | X | . | X | planeado (M6)
store_activity | fact_store_activity | X | . | X | planeado (M6)
returns | fact_returns | X | X | X | hipotetico (fuera de esta guia)
Con returns agregado, dim_product deja de ser exclusiva de orders — ahora la comparten dos procesos, y técnicamente ya calificaría como conformada. Este ejercicio es puramente hipotético —esta guía no construye fact_returns en ningún módulo—, pero muestra cómo el mapa se actualiza naturalmente a medida que un warehouse real crece con más procesos de negocio.
Ejercicio 2 — Calcula qué proceso usa MÁS dimensiones. Usando BUS_MATRIX del ejemplo trabajado (sin el proceso hipotético del ejercicio 1), escribe código Python que identifique cuál de los tres procesos actuales usa el mayor número de dimensiones.
Ver solución
most_dimensions = max(BUS_MATRIX, key=lambda row: len(row[3]))
print(f"El proceso con mas dimensiones: {most_dimensions[0]} ({len(most_dimensions[3])} dimensiones)")
Salida esperada:
El proceso con mas dimensiones: orders (3 dimensiones)
orders usa las tres dimensiones (dim_store, dim_product, dim_date), mientras que sessions y store_activity usan solo dos cada uno. Esto tiene sentido con lo que ya sabes del grano de cada proceso: fact_orders describe una venta específica de un producto específico —necesita dim_product—, mientras que fact_sessions y fact_store_activity describen comportamiento agregado por tienda y por fecha, sin descender al nivel de producto individual.
Ejercicio 3 — Explica, sin código, por qué dim_date casi siempre termina siendo la dimensión más conformada de cualquier warehouse. En 2-3 frases, usando lo que sabes de los tres procesos de Kiosko (existentes y planeados), explica por qué el calendario tiende a aparecer en casi todos los procesos de negocio de una empresa, mucho más que cualquier otra dimensión.
Ver solución
Casi cualquier evento de negocio ocurre en un momento específico del tiempo —una venta, una sesión de navegación, un cierre de actividad diaria—, así que casi cualquier proceso necesita, de una forma u otra, anclarse a una fecha para poder analizarse por día, semana o mes. En cambio, no todos los procesos necesitan describir un producto específico (como viste con fact_sessions y fact_store_activity, que no lo necesitan) o incluso una tienda específica (en un negocio distinto a Kiosko, podría haber procesos completamente digitales sin ninguna ubicación física). El tiempo es, en ese sentido, la dimensión más universal que existe — la razón por la que Kimball la trata como la primera dimensión conformada que casi cualquier warehouse construye, mucho antes que cualquier otra.
Resumen y siguiente paso
En esta lección construiste el bus matrix de Kiosko: una tabla de planeación —procesos de negocio en filas, dimensiones en columnas— que confirma, de un vistazo, lo que la lección anterior ya había encontrado comparando un par de procesos: dim_store y dim_date son conformadas entre los tres procesos de Kiosko (uno construido, dos planeados para el módulo 6), mientras que dim_product sigue siendo específica del proceso de ventas. Aprendiste que esta herramienta se construye antes de escribir código, con la visión completa del warehouse, precisamente para evitar el error de duplicar una dimensión que ya existe en otro proceso.
Antes de avanzar deberías poder: dibujar de memoria el bus matrix de Kiosko con sus tres procesos y tres dimensiones; explicar por qué el nombre "bus matrix" viene de un sistema eléctrico compartido, no de un vehículo; y nombrar la dimensión que, en casi cualquier warehouse, termina siendo la más conformada de todas.
Con las cuatro tablas construidas —fact_orders, dim_store, dim_product, dim_date— y el mapa completo de cómo se relacionan, la lección 7 hace lo que este módulo entero venía preparando: ensamblar el primer star real de Kiosko, con los tres JOIN ejecutados de verdad, y verificar que ninguno pierde ni duplica ni una sola fila.
Recursos
- Kimball Group — "Star Schema / OLAP Cube" — la fuente que documenta la arquitectura de bus (bus architecture) y el bus matrix como herramienta central de planeación dimensional. kimballgroup.com/data-warehouse-business-intelligence-resources/kimball-techniques/dimensional-modeling-techniques/star-schema-olap-cube. En inglés.
- "The Data Warehouse Toolkit", 3ra edición (Kimball & Ross, Wiley) — desarrolla en detalle la construcción del bus matrix como el primer paso de cualquier proyecto de modelado dimensional a escala de empresa. wiley.com/en-jp/The+Data+Warehouse+Toolkit. En inglés.