Módulo 1: From File Format To Table Format

Formato de archivo vs formato de tabla

Descripción

Esta lección da el paso conceptual que hace posible entender todo lo que sigue: la distinción precisa, sin ambigüedad, entre un formato de archivo (lo que Parquet es) y un formato de tabla (lo que Iceberg es). No son dos alternativas que compiten por resolver el mismo problema — son dos capas distintas, una encima de la otra, y confundirlas es la fuente más común de malentendidos sobre qué es Iceberg y qué no es.

Conexión con el módulo. La lección 2 mostró, con evidencia, cuatro veces que el ecosistema de Kiosko necesitó algo que un formato de archivo, por sí solo, no da. Esta lección nombra con precisión qué es ese algo. Las lecciones 4 a 8 de este módulo instalan y usan Iceberg por primera vez; esta lección es la última parada conceptual antes de escribir código.

Una analogía: la caja de fotos sueltas y el álbum con índice, otra vez, con más detalle

La lección 1 de este módulo introdujo la analogía: un archivo Parquet es como una caja de fotos sueltas, bien reveladas, pero sin ningún índice que las organice; una tabla Iceberg es como un álbum con un índice al frente. Vale la pena llevar esa analogía un paso más allá, porque la distinción exacta importa.

Fíjate en algo importante: las fotos en sí —el papel, la revelación, la nitidez— son exactamente las mismas en ambos casos. El álbum no reveló las fotos de nuevo con una técnica distinta; simplemente les agregó un índice. De la misma forma, los archivos de datos de una tabla Iceberg son Parquet, punto — el mismo formato columnar, comprimido, tipado, que ya usaste en las seis guías anteriores. Iceberg no reemplaza cómo se guardan los bytes de una fila; agrega, por encima, una capa que sabe: cuántas fotos hay ahora mismo, cuáles había ayer, en qué orden se agregaron, y cómo reconstruir cualquier versión anterior sin haber tenido que guardarla aparte a propósito.

Esa es, con precisión, la definición de esta lección: un formato de archivo describe cómo se guardan los bytes de un conjunto de filas. Un formato de tabla describe cómo esos archivos se organizan, versionan y consultan como si fueran una sola entidad lógica llamada "tabla".

Ejemplo trabajado: la misma pregunta, respondida por un archivo y por una tabla

El ejemplo trabajado de la lección 1 mostró que un Parquet suelto, leído con pyarrow.parquet.read_table(), puede decirte cuántas filas tiene y con qué esquema — ahora mismo, nada más. Compara esa respuesta con la que da PyIceberg sobre la tabla que vas a construir en las lecciones 5 y 6 de este mismo módulo (adelanto: el código completo y la instalación llegan en la lección 4; aquí solo se muestra la forma de la pregunta y la respuesta, para contrastarla):

# la pregunta que un archivo Parquet responde
import pyarrow.parquet as pq
pa_table = pq.read_table("fact_orders.parquet")
print(pa_table.num_rows)          # 40 -- pero "40, segun que version?"

# la misma pregunta, respondida por una tabla Iceberg
table = catalog.load_table("kiosko.fact_orders")
print(table.scan().to_arrow().num_rows)      # 40 -- la version VIGENTE
print(table.history())                        # la lista COMPLETA de versiones
print(table.scan(snapshot_id=snap_v1).to_arrow().num_rows)  # 40 -- una version ESPECIFICA, por id

La primera pregunta —pa_table.num_rows— solo tiene una respuesta posible, porque solo hay una versión: la que está en el archivo, en este momento, sin ninguna forma de preguntar por otra. La segunda pregunta —table.scan().to_arrow().num_rows— tiene la misma respuesta numérica hoy (40), pero es una respuesta de un tipo distinto: es la respuesta a "¿cuántas filas tiene la versión vigente?", una pregunta que admite una tercera forma —table.scan(snapshot_id=snap_v1)— que un archivo Parquet suelto no puede formular ni responder, porque no tiene noción de "una versión distinta a la actual". No necesitas entender todavía la sintaxis completa de table.history() o de snapshot_id —eso es, con precisión, el contenido del módulo 3 de esta guía—; lo que esta comparación muestra, en este punto exacto de la guía, es la diferencia de vocabulario disponible: un archivo solo puede hablar de "lo que hay"; una tabla puede hablar de "lo que hay, lo que hubo, y cómo llegamos de uno a otro".

Las seis capacidades que un formato de tabla agrega, y dónde las vas a ver

Iceberg agrega, encima del mismo Parquet de siempre, seis capacidades concretas que ningún archivo suelto puede dar por sí solo. No vas a construir las seis en este módulo —cada una tiene su propio módulo dedicado más adelante en esta guía—, pero vale la pena nombrarlas todas aquí, una vez, con precisión:

  1. Transacciones ACID reales. Una escritura nunca deja la tabla a medio camino — o se aplicó completa, o no se aplicó nada. Contrasta directamente con la ventana de riesgo del overwrite-partition de la lección 2. (Se profundiza en el módulo 4.)
  2. Snapshots automáticos en cada commit. Cada escritura crea una versión nueva, inmutable, sin que nadie tenga que declarar una columna de historia. (Módulo 3.)
  3. Time travel. Consultar cualquier snapshot anterior por su identificador, reconstruyendo el pasado exacto de la tabla sin valid_from/valid_to escritos por nadie. (Módulo 3.)
  4. Evolución de esquema segura. Agregar, renombrar o borrar una columna sin reescribir un solo archivo de datos existente. (Módulo 4.)
  5. Partición oculta y evolución de partición. Las consultas filtran por columna de negocio, nunca por estructura de carpetas; el esquema de partición se puede cambiar hacia adelante sin tocar los datos ya escritos. (Módulo 5.)
  6. MERGE INTO / upserts nativos. El mismo problema de "actualizar sin perder historia" que data-modeling resolvió a mano y dbt automatizó con columnas, ahora resuelto como una operación propia del formato. (Módulo 6.)

Fíjate en que las seis capacidades no son ideas sueltas — cada una responde, con nombre y apellido, a uno de los cuatro problemas de la lección 2. Las capacidades 2 y 3 responden a los problemas 2 y 3 (historia de dim_product). La capacidad 1 responde al problema 1 (overwrite-partition). La capacidad 5 responde al problema 4 (carpetas Hive). Y la capacidad 6 vuelve a poner el problema del cambio de P002 sobre la mesa, esta vez resuelto nativamente en vez de con columnas.

Diagrama: dos capas, una encima de la otra

flowchart TB
    subgraph TABLA["Formato de TABLA (Iceberg) -- el algo por encima"]
        T1["Catalogo: apunta al metadata vigente"]
        T2["Metadata: esquema, snapshots, particion"]
        T3["ACID / snapshots / time travel /\nevolucion de esquema / particion oculta / MERGE"]
    end
    subgraph ARCHIVO["Formato de ARCHIVO (Parquet) -- sin cambios"]
        A1["Codificacion columnar"]
        A2["Compresion (snappy/zstd)"]
        A3["Tipos de dato por columna"]
    end
    TABLA -->|"organiza, versiona\ny apunta a"| ARCHIVO

Profundización: por qué esta distinción no es solo semántica

Es tentador tratar "formato de archivo vs formato de tabla" como una diferencia de vocabulario sin consecuencias prácticas. No lo es, y vale la pena decir por qué con un ejemplo concreto: si mañana alguien te pide "compara el revenue de esta semana contra el de la semana pasada, exactamente como se veían en el momento en que cada una terminó", con un Parquet suelto la única forma de responder es haber guardado, a propósito, una copia separada de cada semana —una carpeta week_2026_08_03/, otra week_2026_08_10/—, una disciplina manual que alguien tiene que mantener para siempre, sin ningún error posible. Con una tabla Iceberg, esa pregunta se responde con dos números de snapshot_id, capturados automáticamente por el motor en el momento exacto de cada escritura — nadie tuvo que acordarse de nada, porque el formato de tabla ya lo hizo por diseño. Esa diferencia —disciplina manual permanente, contra garantía automática del formato— es, con precisión, lo que separa "un formato de archivo bien usado" de "un formato de tabla real". El módulo 3 de esta guía construye exactamente ese ejemplo, con el cambio real de P002.

Errores comunes

Pensar que "tabla" es solo un directorio con varios archivos Parquet adentro. Qué pasa: alguien, al ver que una tabla Iceberg vive, en disco, como una carpeta con subcarpetas data/ y metadata/, concluye que Iceberg es simplemente "una convención de organizar carpetas", parecida al particionado Hive del problema 4 de la lección 2. Por qué pasa: visualmente, ambas cosas son carpetas con archivos adentro. Cómo detectarlo: si crees que podrías reconstruir el comportamiento de Iceberg simplemente organizando tus propios Parquets en subcarpetas con nombres convencionales, te falta la pieza central — no es la organización de carpetas lo que hace la diferencia, es el archivo de metadata (JSON, que el módulo 2 de esta guía inspecciona a fondo) que registra, con garantías transaccionales, cuál es la versión vigente y cuáles fueron las anteriores. Cómo corregirlo: el módulo 2 completo está dedicado a esta distinción exacta — vas a abrir, tú mismo, el directorio warehouse/ que este módulo va a crear, y vas a ver que lo que hace la diferencia no es dónde viven los archivos, sino qué apunta a qué.

Creer que hay que elegir entre "usar Parquet" o "usar Iceberg". Qué pasa: alguien entiende la comparación de esta lección como una elección entre dos tecnologías competidoras, del mismo modo en que se elige entre dos bases de datos. Por qué pasa: el lenguaje de "formato A vs formato B" invita, por costumbre, a pensar en alternativas mutuamente excluyentes. Cómo detectarlo: si te preguntas "¿debería usar Parquet o Iceberg para este proyecto?", la pregunta está mal planteada — repasa el diagrama de esta lección: Iceberg usa Parquet como su formato de archivo de datos, no compite con él. Cómo corregirlo: la pregunta correcta es "¿este Parquet necesita comportarse como una tabla (con historia, con evolución segura, con garantías transaccionales), o alcanza con ser un archivo bien escrito?" — la lección 6 de este módulo vas a ver, en código, que el mismo fact_orders.parquet de siempre se convierte en la tabla Iceberg sin haber cambiado un solo byte de cómo se codifican sus filas.

Ejercicios

Ejercicio 1 — Clasifica cada capacidad. Para cada una de las siguientes, di si es una capacidad de formato de archivo (Parquet) o de formato de tabla (Iceberg): (a) compresión columnar de una columna numérica; (b) consultar cómo se veía la tabla completa hace tres semanas; (c) tipos de dato por columna dentro de un único archivo; (d) agregar una columna nueva sin reescribir los datos existentes.

Ver solución

(a) formato de archivo — la compresión (snappy, zstd) es una propiedad de cómo Parquet codifica los bytes de una columna, independiente de si ese Parquet vive suelto o dentro de una tabla Iceberg. (b) formato de tabla — es exactamente time travel, una capacidad que depende de que exista un historial de snapshots, algo que un archivo suelto no tiene. (c) formato de archivo — el esquema tipado por columna es una propiedad nativa de Parquet, presente incluso en un archivo .parquet completamente suelto, sin ningún catálogo. (d) formato de tabla — evolución de esquema segura depende de que el formato de tabla sepa cómo interpretar archivos viejos (sin la columna nueva) y archivos nuevos (con ella) como una sola tabla coherente.

Ejercicio 2 — Explica con tus propias palabras por qué Iceberg "no revela las fotos de nuevo". Retomando la analogía del álbum, explica en 2-3 frases por qué es correcto decir que Iceberg no cambia cómo se codifican los datos dentro de cada archivo Parquet.

Ver solución

Iceberg agrega una capa de organización y versionado por encima de los archivos Parquet —el catálogo y la cadena de metadata—, pero cada archivo de datos individual sigue siendo un .parquet normal, escrito con la misma codificación columnar, la misma compresión y los mismos tipos que ya usaste en las guías anteriores. La prueba concreta está en la lección 6 de este módulo: el mismo fact_orders.parquet reconstruido con pyarrow se carga dentro de la tabla Iceberg con table.append(), sin que ningún paso intermedio "revele las fotos de nuevo" con una técnica distinta — solo se les agrega un índice.

Ejercicio 3 — Predicción: ¿qué pasa si abres un archivo de datos de Iceberg directamente con pandas? Sin haber instalado Iceberg todavía, predice: si en la lección 6 de este módulo abrieras, con pandas.read_parquet(), directamente uno de los archivos de datos que Iceberg escribió dentro de warehouse/kiosko/fact_orders/data/, saltándote el catálogo por completo, ¿esperas que funcione? ¿Por qué?

Ver solución

Sí, debería funcionar sin ningún error — porque, tal como explica esta lección, un archivo de datos de una tabla Iceberg es un .parquet completamente normal, legible con cualquier herramienta que ya sabe leer Parquet, sin necesitar el catálogo ni ninguna pieza de Iceberg. Lo que no vas a obtener leyéndolo así es el contexto de tabla: no vas a saber si ese archivo específico pertenece al snapshot vigente o a uno anterior, ni vas a poder pedirle una versión distinta — para eso sí necesitas pasar por el catálogo y la API de PyIceberg, exactamente como muestra el ejemplo trabajado de esta lección.

Resumen y siguiente paso

En esta lección definiste, con precisión, la distinción central de toda la guía: un formato de archivo (Parquet) describe cómo se codifican los bytes de un conjunto de filas; un formato de tabla (Iceberg) describe cómo esos archivos se organizan, versionan y consultan como una sola entidad lógica. Viste las seis capacidades concretas que Iceberg agrega, y el mapa de en qué módulo de esta guía se construye cada una.

Antes de avanzar deberías poder: explicar, sin usar la palabra "mejor", en qué se diferencia un formato de archivo de un formato de tabla; y nombrar las seis capacidades de Iceberg, aunque sea sin el detalle técnico de cada una todavía.

Con esta base conceptual lista, la lección 4 deja la teoría atrás por el resto del módulo: instala PyIceberg de verdad, en tu propia máquina, y crea el primer catálogo local de Kiosko.

Recursos

  • Apache Iceberg — documentación oficial, "What is Iceberg?", la definición formal de formato de tabla y su relación con los formatos de archivo que organiza. iceberg.apache.org/docs/latest. En inglés.
  • Apache Parquet — documentación oficial, la especificación del formato de archivo columnar que Iceberg usa sin modificar. parquet.apache.org/docs. En inglés.
  • PyIceberg — referencia de API, sintaxis exacta de table.scan(), table.history() y table.scan(snapshot_id=...) usadas en el ejemplo trabajado de esta lección — a fondo desde el módulo 3. py.iceberg.apache.org/api. En inglés.
  • DISEÑO de esta guía — el mapa completo de las seis capacidades y en qué módulo se construye cada una. src/guides/lakehouse-and-iceberg-guide/DISENO.md. En español.