¿Qué es Apache Parquet?
Apache Parquet es un formato de almacenamiento de datos orientado a columnas, de código abierto, diseñado para su uso con frameworks de procesamiento de big data. Desarrollado originalmente por Twitter y Cloudera en 2013 para el ecosistema Hadoop, Parquet es ahora un proyecto de la Apache Software Foundation y el estándar de facto para el almacenamiento de datos analíticos en data lakes, almacenes de datos en la nube y pipelines de big data.
Parquet se usa ampliamente en:
- Apache Spark, Hive, Impala — procesamiento del ecosistema Hadoop
- Amazon Athena, AWS Glue — análisis SQL sin servidor en S3
- Google BigQuery — formato de exportación/importación para datos externos
- Snowflake, Databricks — integraciones de plataformas de datos
- DuckDB, pandas, Arrow — análisis en proceso
Almacenamiento orientado a filas vs. orientado a columnas
Para entender Parquet, primero necesitas entender la diferencia entre almacenamiento orientado a filas (OLTP) y orientado a columnas (OLAP):
Almacenamiento orientado a filas (CSV, SQLite, etc.)
Fila 1: "Alice", 30, "Ingeniero", 85000
Fila 2: "Bob", 25, "Diseñador", 72000
Todas las columnas de una fila se almacenan contiguamente. Excelente para leer/escribir filas individuales. Ineficiente para agregar una sola columna a través de muchas filas.
Almacenamiento orientado a columnas (Parquet)
Columna Nombre: "Alice", "Bob"
Columna Edad: 30, 25
Columna Salario: 85000, 72000
Todos los valores de una columna se almacenan contiguamente. Excelente para consultas analíticas que agregan o filtran columnas específicas.
Por qué importa: Para un conjunto de datos con 100 columnas y 100 millones de filas, una consulta que filtra 3 columnas lee solo el 3/100 del total de datos en Parquet, vs. leer las 100 columnas por fila en un formato orientado a filas.
Estructura del archivo Parquet
Un archivo Parquet está organizado en tres niveles de anidamiento:
Archivo Parquet
├── Grupo de filas 1 (~128 MB predeterminado)
│ ├── Fragmento de columna (Columna A, todas las filas del grupo)
│ │ ├── Páginas de datos (codificadas + comprimidas)
│ ├── Fragmento de columna (Columna B)
│ └── Fragmento de columna (Columna N)
│
├── Grupo de filas 2
│ └── Fragmentos de columnas...
│
└── Pie de página (Metadatos del archivo)
├── Esquema (nombres de columnas, tipos)
├── Metadatos de grupos de filas
│ └── Estadísticas por columna (min, max, null_count)
└── Metadatos clave-valor
Codificaciones de Parquet
Parquet usa varias codificaciones especializadas que reducen dramáticamente el tamaño de almacenamiento:
Codificación de diccionario
Para columnas con baja cardinalidad (pocos valores únicos), Parquet construye un diccionario de valores únicos y reemplaza cada valor con su índice de diccionario.
Antes: "activo" (6 bytes) × 10M = 60 MB
Después: Diccionario: {0: "activo", 1: "inactivo", 2: "pendiente"}
Datos: 0, 0, 1, 0, 2, ... (2 bits por valor) = 2.5 MB
Run-Length Encoding (RLE)
Para datos repetitivos, RLE almacena pares (valor, recuento) en lugar de valores repetidos:
Antes: 1, 1, 1, 1, 1, 2, 2, 2, 3, 3 (10 valores)
Después: (1, 5), (2, 3), (3, 2) (3 pares)
Codificación delta
Para valores que aumentan monotónicamente (marcas de tiempo, IDs secuenciales):
Antes: 1000, 1001, 1003, 1006
Después: base=1000, deltas=[1, 2, 3]
Compresión de Parquet
| Codec | Relación de compresión | Velocidad de descompresión | Caso de uso |
|---|---|---|---|
| Snappy | Moderada | Muy rápida | Predeterminado; rendimiento equilibrado |
| GZIP | Buena | Moderada | Mejor compresión, CPU moderada |
| LZ4 | Moderada | Más rápida | Mínima latencia |
| ZSTD | Muy buena | Rápida | Mejor equilibrio ratio/velocidad |
ZSTD es el codec moderno recomendado — logra mejor compresión que Snappy con velocidad de descompresión similar.
Lectura y escritura de Parquet
Python (PyArrow)
import pyarrow as pa
import pyarrow.parquet as pq
# Escribir Parquet
tabla = pa.Table.from_pydict({
'nombre': ['Alice', 'Bob', 'Carol'],
'edad': [30, 25, 35],
'salario': [85000, 72000, 95000]
})
pq.write_table(tabla, 'empleados.parquet', compression='zstd')
# Leer Parquet
tabla = pq.read_table('empleados.parquet')
df = tabla.to_pandas()
# Leer solo columnas específicas
tabla = pq.read_table('empleados.parquet', columns=['nombre', 'salario'])
SQL (DuckDB)
-- Consultar Parquet directamente con SQL
SELECT avg(salario), rol FROM 'empleados.parquet' GROUP BY rol;
-- Convertir CSV a Parquet
COPY (SELECT * FROM 'datos_grandes.csv') TO 'salida.parquet' (FORMAT PARQUET, COMPRESSION ZSTD);
Parquet vs. CSV para análisis
| Característica | CSV | Parquet |
|---|---|---|
| Legible por humanos | ✅ | ❌ |
| Esquema | ❌ (inferido) | ✅ (incrustado) |
| Compresión | Mala (texto) | Excelente (tipado, codificado) |
| Proyección de columnas | Lee todas las columnas | Lee solo las columnas necesarias |
| Pushdown de predicados | Ninguno | Sí (estadísticas de grupos de filas) |
| Tamaño típico | 100% | 10-30% del tamaño CSV |
Un archivo CSV de 10 GB podría convertirse en un archivo Parquet de 1-2 GB con compresión ZSTD, mientras que es más rápido de consultar analíticamente porque solo se leen las columnas relevantes.
Conversiones relacionadas
Conversiones frecuentes del catálogo: