jupyternotebookduckdbdata-sciencepython

Jupyter Notebook en Tu Data Lake en 60 Segundos

Michael San Martim · 2026-04-27

Quieres explorar tu data lake en un notebook de Jupyter. Así es cómo normalmente se ve:

  1. Instalar JupyterLab
  2. Instalar DuckDB y los bindings de Python
  3. Averiguar en qué bucket S3 están tus datos
  4. Instalar boto3 y configurar credenciales de AWS
  5. Escribir el boilerplate de configuración de DuckDB para S3
  6. Descubrir manualmente qué tablas existen
  7. Escribir las sentencias de lectura de Parquet para cada tabla
  8. Esperar que las rutas estén bien

Son 20 minutos de configuración antes de escribir una sola consulta analítica. Cada vez.

La Forma DataSpoc Lens

Terminal window
dataspoc-lens add-bucket company s3://company-data-lake
dataspoc-lens notebook

Eso es todo. JupyterLab se abre en tu navegador con cada tabla de tu data lake ya montada cómo una vista de DuckDB. La magia SQL funcióna de inmediato. La variable conn está lista para pandas.

Qué Sucede Por Debajo

Cuando ejecutas dataspoc-lens notebook, Lens:

  1. Lee el manifiesto de s3://company-data-lake/.dataspoc/manifest.json
  2. Crea una conexión DuckDB con credenciales S3 de tu entorno
  3. Monta cada ruta Parquet cómo una vista con nombre
  4. Genera un script de inicio (~/.dataspoc/jupyter_startup.py)
  5. Lanza JupyterLab con el script de inicio precargado

El script de inicio se ve así (auto-generado, nunca lo editas):

# ~/.dataspoc/jupyter_startup.py (auto-generated)
import duckdb
conn = duckdb.connect()
# S3 configuration (from environment)
conn.execute("INSTALL httpfs; LOAD httpfs;")
conn.execute("SET s3_region = 'us-east-1';")
# Mount all tables from manifest
conn.execute("""
CREATE VIEW raw__postgres__orders AS
SELECT * FROM read_parquet('s3://company-data-lake/raw/postgres/orders/*.parquet')
""")
conn.execute("""
CREATE VIEW raw__postgres__customers AS
SELECT * FROM read_parquet('s3://company-data-lake/raw/postgres/customers/*.parquet')
""")
conn.execute("""
CREATE VIEW curated__sales__customers AS
SELECT * FROM read_parquet('s3://company-data-lake/curated/sales/customers/*.parquet')
""")
# ... one view per table in your lake
print(f"DataSpoc Lens: {len(conn.execute('SHOW TABLES').fetchall())} tables mounted")
print("Use 'conn' for queries or %%sql magic for inline SQL")

Ejemplo de Celdas del Notebook

Celda 1: Ver Qué Está Disponible

# All your tables are already here
conn.sql("SHOW TABLES").show()
┌─────────────────────────────────────┐
│ name │
├─────────────────────────────────────┤
│ raw__postgres__orders │
│ raw__postgres__customers │
│ raw__postgres__order_items │
│ curated__sales__customers │
│ raw__google_sheets__campaigns │
└─────────────────────────────────────┘

Celda 2: Magia SQL

%%sql
SELECT
DATE_TRUNC('month', created_at) as month,
COUNT(*) as orders,
SUM(amount) as revenue
FROM raw__postgres__orders
WHERE created_at >= '2026-01-01'
GROUP BY month
ORDER BY month
┌────────────┬────────┬───────────┐
│ month │ orders │ revenue │
├────────────┼────────┼───────────┤
│ 2026-01-01 │ 3,421 │ 284,500 │
│ 2026-02-01 │ 3,892 │ 312,100 │
│ 2026-03-01 │ 4,156 │ 341,800 │
│ 2026-04-01 │ 2,847 │ 228,400 │
└────────────┴────────┴───────────┘

Celda 3: Pandas DataFrame

df = conn.sql("""
SELECT
customer_id,
COUNT(*) as order_count,
SUM(amount) as total_spend,
MAX(created_at) as last_order
FROM raw__postgres__orders
GROUP BY customer_id
""").df()
df.describe()
order_count total_spend
count 3201.000000 3201.000000
mean 14.340000 832.450000
std 8.230000 456.780000
min 1.000000 12.990000
max 89.000000 8945.000000

Celda 4: Gráfico con Matplotlib

import matplotlib.pyplot as plt
monthly = conn.sql("""
SELECT
DATE_TRUNC('month', created_at) as month,
SUM(amount) as revenue
FROM raw__postgres__orders
WHERE created_at >= '2025-01-01'
GROUP BY month
ORDER BY month
""").df()
plt.figure(figsize=(12, 5))
plt.bar(monthly["month"].dt.strftime("%b %Y"), monthly["revenue"])
plt.title("Monthly Revenue")
plt.ylabel("Revenue ($)")
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()

Celda 5: Cruzar Múltiples Fuentes

%%sql
SELECT
c.channel,
COUNT(DISTINCT o.customer_id) as customers,
SUM(o.amount) as revenue,
ROUND(SUM(o.amount) / COUNT(DISTINCT o.customer_id), 2) as avg_revenue_per_customer
FROM raw__postgres__orders o
JOIN raw__postgres__customers cu ON o.customer_id = cu.id
JOIN raw__google_sheets__campaigns c ON cu.utm_source = c.channel
GROUP BY c.channel
ORDER BY revenue DESC

La Alternativa Marimo

¿Prefieres notebooks reactivos? Lens también soporta Marimo:

Terminal window
dataspoc-lens notebook --runtime marimo

Esto lanza un notebook Marimo con las mismas tablas pre-montadas:

import marimo as mo
import duckdb
# conn is pre-configured (same startup script)
conn = duckdb.connect()
# ... tables already mounted
# Marimo's built-in SQL support
result = mo.sql("""
SELECT channel, SUM(amount) as revenue
FROM raw__postgres__orders
GROUP BY channel
""", connection=conn)
# Reactive: change the query, chart updates automatically
mo.ui.table(result)

Ventajas de Marimo:

  • Ejecución reactiva (las celdas se re-ejecutan cuando cambian las dependencias)
  • Widgets de UI integrados (sliders, dropdowns)
  • Reproducible (sin estado oculto)
  • Se exporta a scripts Python

Demo Docker: Entorno Completamente Autocontenido

¿Quieres probarlo sin instalar nada? Usa la demo Docker:

Terminal window
docker run -it --rm \
-p 8888:8888 \
-e AWS_ACCESS_KEY_ID \
-e AWS_SECRET_ACCESS_KEY \
-e AWS_DEFAULT_REGION \
dataspoc/lens-notebook:latest \
--bucket s3://company-data-lake

Esto te da:

  • JupyterLab corriendo en http://localhost:8888
  • DuckDB con todas las tablas de tu bucket montadas
  • Magia %%sql preconfigurada
  • pandas, matplotlib, seaborn, plotly preinstalados
  • Variable conn lista para usar

Docker Compose para Uso en Equipo

docker-compose.yaml
version: "3.8"
services:
notebook:
image: dataspoc/lens-notebook:latest
ports:
- "8888:8888"
environment:
- AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY
- AWS_DEFAULT_REGION
- DATASPOC_BUCKET=s3://company-data-lake
volumes:
- ./notebooks:/home/jovyan/notebooks
Terminal window
docker compose up

Comparte el docker-compose.yaml con tu equipo. Todos obtienen el mismo entorno, mismas tablas, mismas vistas SQL. Sin problemas de “funcióna en mi máquina”.

Consejos

Múltiples buckets:

Terminal window
dataspoc-lens add-bucket sales s3://company-sales
dataspoc-lens add-bucket marketing s3://company-marketing
dataspoc-lens notebook
# Both buckets' tables are mounted

Refrescar tablas sin reiniciar:

# In a notebook cell
from dataspoc_lens import LensClient
lens = LensClient()
lens.refresh() # Re-reads manifest, mounts new tables

Usar con VS Code Jupyter:

Terminal window
dataspoc-lens notebook --no-browser --ip 0.0.0.0
# Then connect VS Code to the running Jupyter server

El Resumen en 60 Segundos

PasoComandoTiempo
Conectar bucketdataspoc-lens add-bucket company s3://...2s
Lanzar notebookdataspoc-lens notebook5s
Empezar a consultar%%sql SELECT ...0s (las tablas ya están ahí)

Sin boto3. Sin configuración de credenciales. Sin adivinar rutas de Parquet. Sin boilerplate de configuración de DuckDB.

Solo abre el notebook y escribe SQL.

Recomendados