(+351) 21 24 10006  ·  info@bconcepts.pt
Carnaxide, Lisboa

Como versionar esquemas em Lakehouse: passo a passo

João Barros 23 de September de 2026 5 min de leitura

Este tutorial mostra como implementar versionamento de esquemas em Lakehouse para gerir alterações de esquema em tabelas Delta, evitando que pipelines ETL falhem quando chegam novas colunas ou tipos diferentes. A técnica permite validar, aplicar e reverter alterações de esquema de forma controlada.

Pré-requisitos

  • Conta com acesso ao Microsoft Fabric/Workspace com permissões para criar Lakehouse e executar notebooks.
  • Conhecimentos básicos de Spark/PySpark e Delta Lake.
  • Exemplo de dados de ingestão em CSV ou Parquet e acesso ao OneLake/Storage do Lakehouse.

Passo 1: Conceito e estratégia de versionamento

Porquê versionar: alterações de esquema (colunas novas, removidas ou tipo diferente) podem quebrar consumos e jobs. A estratégia simples é manter um ficheiro de esquema por versão (JSON), validar a entrada, aplicar transformação compatível e gravar uma nova versão Delta ou criar um alias/view para a versão corrente.

Passo 2: Definir esquemas em JSON

Crie ficheiros JSON com a definição do esquema esperada. Mantém cada versão clara (v1, v2...). Isto permite comparar programaticamente.

# exemplo de schema v1 (schema_v1.json)
{
  "fields": [
    {"name": "id", "type": "long", "nullable": false},
    {"name": "nome", "type": "string", "nullable": true},
    {"name": "valor", "type": "double", "nullable": true}
  ]
}

# exemplo de schema v2 (schema_v2.json) adiciona coluna 'categoria'
{
  "fields": [
    {"name": "id", "type": "long", "nullable": false},
    {"name": "nome", "type": "string", "nullable": true},
    {"name": "valor", "type": "double", "nullable": true},
    {"name": "categoria", "type": "string", "nullable": true}
  ]
}

Passo 3: Carregar dados de ingestão e inferir esquema

Carrega o ficheiro de entrada e transforma os tipos; compara com o esquema esperado usando PySpark. Se necessário, aplica coerção de tipos ou adiciona colunas em falta com valores nulos/padrão.

from pyspark.sql import SparkSession
from pyspark.sql.types import StructType
import json

spark = SparkSession.builder.getOrCreate()

# caminho para o CSV de ingestão
input_path = '/mnt/lakehouse/raw/ingest/input.csv'

df = spark.read.option('header', 'true').csv(input_path)

# carregar esquema esperado (v2) do JSON
with open('/dbfs/mnt/lakehouse/schemas/schema_v2.json') as f:
    schema_json = json.load(f)
    # converter para StructType simples: exemplo mínimo
    expected_fields = [(f['name'], f['type']) for f in schema_json['fields']]

# função simples de coerção/ajuste
for name, typ in expected_fields:
    if name not in df.columns:
        df = df.withColumn(name, spark.sql.functions.lit(None).cast('string'))

# coerção de tipo mínima (exemplo): cast para double quando requerido
if 'valor' in df.columns:
    df = df.withColumn('valor', df['valor'].cast('double'))

Passo 4: Validar e registar incompatibilidades

Valida se existem colunas extra, tipos incompatíveis ou chaves primárias ausentes. Regista problemas num ficheiro de auditoria para permitir fallback.

# detectar colunas extra
expected_names = [f[0] for f in expected_fields]
extra = [c for c in df.columns if c not in expected_names]

# exemplo de registo simples
audit = {
  'input_path': input_path,
  'expected_schema': expected_names,
  'found_columns': df.columns,
  'extra_columns': extra
}

# grava audit como JSON numa pasta de governação
import json
with open('/dbfs/mnt/lakehouse/audit/schema_audit.json', 'w') as f:
    f.write(json.dumps(audit))

Passo 5: Aplicar transformação compatível e gravar como tabela Delta

Depois de ajustado, grava os dados numa tabela Delta com a versão do esquema nos metadados (por exemplo, tabela nome_versionada_v2). Mantém tabelas por versão ou atualiza uma view/alias.

target_path = '/mnt/lakehouse/curated/minha_tabela_v2'

# escrever Delta
(df
 .write
 .format('delta')
 .mode('append')
 .save(target_path))

# criar/atualizar uma tabela gerida ou external table (SQL)
spark.sql(f"CREATE TABLE IF NOT EXISTS minha_tabela_v2 USING DELTA LOCATION '{target_path}'")

# opcional: atualizar uma view 'minha_tabela' para apontar para a versão corrente
spark.sql("CREATE OR REPLACE VIEW minha_tabela AS SELECT * FROM minha_tabela_v2")

Passo 6: Fallback e rollback de esquema

Se uma versão nova falhar validações a montante ou a jusante, usa a auditoria e o histórico Delta para reverter: podes apontar a view para a versão anterior ou restaurar a tabela a um snapshot conhecido usando Time Travel.

# exemplo de rollback com time travel (se necessário)
spark.sql("CREATE OR REPLACE VIEW minha_tabela AS SELECT * FROM minha_tabela_v1")

# ou restaurar Delta para um commit anterior via RESTORE/Time Travel (exemplo SQL)
-- RESTORE não é universal; use Time Travel: SELECT * FROM delta.`/path` VERSION AS OF X

Verificar o resultado

Confirma que a tabela/view aponta para a versão correta e que os consumidores conseguem ler os dados sem erros. Verifica o ficheiro de auditoria e inspeciona tipos/colunas com DESCRIBE TABLE ou spark.printSchema().

# verificar esquema
spark.table('minha_tabela').printSchema()

# ver audit
with open('/dbfs/mnt/lakehouse/audit/schema_audit.json') as f:
    print(f.read())

Conclusão

Versionar esquemas em Lakehouse reduz falhas e facilita evoluções controladas: mantêm-se ficheiros JSON de esquema, valida-se a ingestão, aplica-se coerções e regista-se auditoria. Próximos passos: automatizar com um job/orquestrador, adicionar testes de regressão de esquema e integrar com CI/CD. Dica: começa por criar um pequeno conjunto de regras de validação para evitar surpresas em produção.