jupyternotebookduckdbdata-sciencepython

Jupyter Notebook no Seu Data Lake em 60 Segundos

Michael San Martim · 2026-04-27

Você quer explorar seu data lake em um notebook Jupyter. Aqui está o que normalmente parece:

  1. Instalar JupyterLab
  2. Instalar DuckDB e os bindings Python
  3. Descobrir qual bucket S3 tem seus dados
  4. Instalar boto3 e configurar credenciais AWS
  5. Escrever o boilerplate de configuração S3 do DuckDB
  6. Descobrir manualmente quais tabelas existem
  7. Escrever as instruções de leitura de Parquet para cada tabela
  8. Torcer para acertar os caminhos

São 20 minutos de setup antes de escrever uma única query analítica. Toda vez.

O Jeito DataSpoc Lens

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

Pronto. O JupyterLab abre no seu navegador com cada tabela no seu data lake já montada como uma view DuckDB. SQL magic funciona direto. A variável conn está pronta para pandas.

O Que Acontece Por Baixo

Quando você executa dataspoc-lens notebook, o Lens:

  1. Lê o manifesto de s3://company-data-lake/.dataspoc/manifest.json
  2. Cria uma conexão DuckDB com credenciais S3 do seu ambiente
  3. Monta cada caminho Parquet como uma view nomeada
  4. Gera um script de inicialização (~/.dataspoc/jupyter_startup.py)
  5. Inicia o JupyterLab com o script de inicialização pré-carregado

O script de inicialização é assim (auto-gerado, você nunca o edita):

# ~/.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")

Exemplos de Células do Notebook

Célula 1: Ver O Que Está Disponível

# 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 │
└─────────────────────────────────────┘

Célula 2: SQL Magic

%%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 │
└────────────┴────────┴───────────┘

Célula 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

Célula 4: Gráfico 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()

Célula 5: JOIN de Múltiplas Fontes

%%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

A Alternativa Marimo

Prefere notebooks reativos? O Lens também suporta Marimo:

Terminal window
dataspoc-lens notebook --runtime marimo

Isso inicia um notebook Marimo com as mesmas tabelas pré-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)

Vantagens do Marimo:

  • Execução reativa (células re-executam quando dependências mudam)
  • Widgets de UI integrados (sliders, dropdowns)
  • Reprodutível (sem estado oculto)
  • Exporta para scripts Python

Demo Docker: Ambiente Autocontido Completo

Quer experimentar sem instalar nada? Use a 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

Isso te dá:

  • JupyterLab rodando em http://localhost:8888
  • DuckDB com todas as tabelas do seu bucket montadas
  • %%sql magic pré-configurado
  • pandas, matplotlib, seaborn, plotly pré-instalados
  • Variável conn pronta para usar

Docker Compose para Uso em Time

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

Compartilhe o docker-compose.yaml com seu time. Todos recebem o mesmo ambiente, mesmas tabelas, mesmas views SQL. Sem problemas de “funciona na minha máquina”.

Dicas

Múltiplos 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

Atualizar tabelas sem reiniciar:

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

Usar com VS Code Jupyter:

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

O Resumo de 60 Segundos

PassoComandoTempo
Conectar bucketdataspoc-lens add-bucket company s3://...2s
Iniciar notebookdataspoc-lens notebook5s
Começar a consultar%%sql SELECT ...0s (tabelas já estão lá)

Sem boto3. Sem configuração de credenciais. Sem adivinhar caminhos Parquet. Sem boilerplate de setup DuckDB.

Apenas abra o notebook e escreva SQL.

Recomendados