Brains Up AnalyticsBRAINSUPAnalytics
Delta LakePythondelta-rsDatabricksData Engineering

Delta Lake em Python puro: escreva tabelas Delta sem Spark com o pacote deltalake (delta-rs)

Como o pacote deltalake (delta-rs, núcleo em Rust/Arrow) grava tabelas Delta legítimas sem Spark nem JVM — escrita, MERGE, OPTIMIZE e time travel em Python, e onde o Spark ainda vence.

Por Dione Fraga · Databricks Certified Professional10 de setembro de 20265 min de leitura

Existe uma suposição silenciosa em muitos times de dados: "Delta Lake é coisa de Spark". Faz sentido — o Delta nasceu dentro do ecossistema Databricks/Spark, e a maior parte da documentação assume um cluster rodando. Mas essa suposição custa caro quando o trabalho é pequeno. Subir um cluster Spark para gravar algumas centenas de milhares de linhas em uma tabela Delta é como alugar um caminhão para carregar uma caixa: funciona, mas você paga startup, custo de infraestrutura e uma dependência de JVM que não precisava existir.

O pacote deltalake — a interface Python do projeto delta-rs — desfaz essa suposição. Ele implementa o protocolo Delta Lake com núcleo em Rust e Apache Arrow por baixo, e entrega tudo em Python sem tocar em JVM, Spark ou Java. E a parte que muda o jogo para quem já vive no mundo Databricks: a tabela que ele grava é uma tabela Delta legítima — a mesma que o seu workspace Databricks e o Unity Catalog leem depois. Não é um "quase Delta"; é Delta de verdade, no mesmo formato de arquivos e log de transações.

Este artigo mostra o quê, o como e o quando — e onde a fronteira com o Spark realmente fica.

O problema concreto

Boa parte das cargas de um time de dados não é big data. São ingestões de API, arquivos que chegam de hora em hora, exports de sistemas transacionais, dumps de webhook. Volumes que cabem confortavelmente na memória de uma máquina modesta. Para esses casos, o padrão "Spark grava em Delta" tem três problemas:

  1. Tempo de startup. Um cluster leva de segundos a minutos para ficar pronto. Para um job que processa em 4 segundos, o overhead domina.
  2. Custo. Cluster ligado é dinheiro rodando, mesmo ocioso entre micro-lotes.
  3. Peso operacional. JVM, versões de Spark, dependências de conector — uma pilha inteira para manter só para conseguir dar um append.

A pergunta certa não é "Spark ou não Spark para sempre?". É: por que pagar Spark quando o trabalho não pede Spark?

A solução: deltalake (delta-rs)

O delta-rs é uma implementação do Delta Lake escrita em Rust, com bindings para Python. Por ser Arrow-native, ele conversa de forma natural — e muitas vezes com cópia zero — com pandas, Polars, PyArrow, DuckDB, Dask e Daft. Você lê de qualquer uma dessas engines, grava em Delta, e lê de volta em qualquer outra.

Passo 1 — Instalar (uma linha)

pip install deltalake

Sem JDK, sem SPARK_HOME, sem configurar conector. O binário Rust já vem embutido no pacote.

Passo 2 — Gravar a partir de qualquer DataFrame

from deltalake import write_deltalake, DeltaTable
import pandas as pd

df = pd.DataFrame({"dia": ["2026-09-10"], "loja": [42], "vendas": [1830.0]})

# grava (cria a tabela se não existir)
write_deltalake("s3://lake/vendas", df, mode="append")

O parâmetro mode aceita append (adiciona), overwrite (substitui) e trabalha com schema_mode para evolução de schema quando novas colunas aparecem. Funciona em disco local (/data/vendas), em S3, ADLS/Azure e GCS — basta passar as credenciais via storage_options ou variáveis de ambiente.

Trocar pandas por Polars é direto — o Polars inclusive tem df.write_delta(...) por cima do mesmo motor:

import polars as pl
pl.read_parquet("bruto/*.parquet").write_delta("s3://lake/vendas", mode="append")

Passo 3 — Ler, manter e voltar no tempo

dt = DeltaTable("s3://lake/vendas")

# compacta arquivos pequenos e co-localiza dados relacionados
dt.optimize.compact()
dt.optimize.z_order(["dia"])

# lê para a engine que você quiser
df = dt.to_pandas()                 # pandas
ds = dt.to_pyarrow_dataset()        # Arrow / DuckDB / Polars lazy

# time travel: a tabela como estava na versão 0
v0 = DeltaTable("s3://lake/vendas", version=0)

Aqui está o valor que você não precisa construir na mão:

  • Commits ACID. Cada gravação é uma transação atômica registrada no _delta_log. Sem arquivo pela metade, sem leitura suja.
  • Checagem e evolução de schema. A tabela recusa dados incompatíveis; e você libera colunas novas explicitamente quando quiser.
  • Time travel. Todo commit vira uma versão consultável — auditoria, reprocessamento e depuração ficam triviais.
  • Manutenção de layout. optimize.compact() resolve o problema dos "small files"; z_order([...]) melhora o data skipping em filtros multi-coluna.

Bônus — Upsert (MERGE) e CDC leve

Precisa de carga incremental com atualização de registros existentes? O delta-rs expõe merge:

(
    dt.merge(
        source=novos_df,
        predicate="alvo.id = origem.id",
        source_alias="origem",
        target_alias="alvo",
    )
    .when_matched_update_all()
    .when_not_matched_insert_all()
    .execute()
)

É CDC (Change Data Capture) sem montar pipeline de Spark Structured Streaming para um volume que não precisa.

Onde isso brilha — e onde o Spark ainda vence

Adotar delta-rs não é abandonar o Spark. É escolher a ferramenta pela carga.

Use delta-rs quando:

  • A carga cabe (ou quase cabe) na memória de uma máquina: ingestões pequenas e médias.
  • Você roda em funções serverless ou containers pequenos, onde subir Spark é inviável ou caro.
  • Quer testes locais que gravam um Delta idêntico ao de produção.
  • Está dando o primeiro salto de um protótipo em pandas para uma tabela governada, sem reescrever tudo em PySpark.

Fique com o Spark quando:

  • shuffles pesados, joins entre tabelas gigantes ou agregações que estouram a RAM.
  • Você precisa de streaming de alto throughput com garantias de exactly-once em escala.
  • O processamento já vive num cluster Databricks e a distribuição é o gargalo real.

Uma nota de governança: no Databricks/Unity Catalog, tabelas gerenciadas ganham predictive optimization — o OPTIMIZE roda sozinho — e a recomendação atual para layout é liquid clustering em vez de ZORDER/partições. Ou seja: use z_order do delta-rs onde você mesmo cuida da manutenção; deixe o Unity Catalog cuidar quando a tabela é gerenciada por ele.

Conclusão

Delta Lake deixou de ser sinônimo de Spark. Com o pacote deltalake, um script Python de dez linhas grava, lê, otimiza e versiona tabelas Delta — com ACID, checagem de schema e time travel de fábrica — e entrega exatamente o formato que o resto da sua plataforma Databricks/Azure já consome. O ganho não é trocar uma tecnologia por outra: é parar de pagar cluster quando o trabalho não pede cluster, e encurtar a distância entre um protótipo e uma tabela de produção governada.

Se você mantém ingestões pequenas rodando em Spark hoje, vale medir: quanto tempo e custo some quando o write_deltalake assume?

Artigos relacionados

Gostou? Veja os e-books para conteúdo aprofundado.

E-books