Ingestão e Catalogação de Dados no BigQuery¶
No projeto InfoEscola, a "ingestão" de dados no BigQuery seguiu uma estratégia arquitetural otimizada e não tradicional: em vez de realizar uma carga física de cópia dos dados para o armazenamento interno do BigQuery (o que geraria custos de armazenamento duplicado), optou-se por catalogar a Camada Bronze existente no Google Cloud Storage (GCS).
🛠️ Técnicas e Arquitetura Utilizadas¶
A arquitetura escolhida transformou o BigQuery em um motor de consulta sobre um Data Lakehouse, utilizando as seguintes técnicas:
- Tabelas Externas (External Tables): O processo consistiu em criar "ponteiros" no BigQuery que leem os dados brutos diretamente do GCS. Essa abordagem é serverless, não destrutiva (os dados de origem ficam intocados e imutáveis) e altamente eficiente em custos, pois paga-se apenas pela leitura da consulta e não pelo armazenamento em duplicidade.
- Adoção do Formato Parquet: Diferente da extração para arquivos
TSV.GZque exige mapeamento manual, o formato Parquet foi utilizado porque armazena o próprio esquema (nomes e tipos das colunas) internamente. Isso permitiu que o BigQuery descobrisse a estrutura dos dados de forma 100% automática ao ler a instruçãoformat = 'PARQUET'. - Automação via Script Python: Em vez de registrar centenas de tabelas manualmente pela interface, foi desenvolvido um script Python (
02_register_bronze_to_catalog.py) utilizando a bibliotecagoogle-cloud-bigquery. O script acessa o bucket do GCS, descobre automaticamente as pastas e executa as instruções DDL (CREATE OR REPLACE EXTERNAL TABLE) no BigQuery de forma dinâmica. - Auto-descoberta de Particionamento (Hive-style): Para estruturar otimizações futuras de leitura, o script utilizou o parâmetro
hive_partitioning_mode = 'AUTO'. Isso instrui o BigQuery a analisar a estrutura de subpastas do GCS (ex:.../ano=2025/mes=10/) e inferir essas pastas como colunas virtuais para viabilizar a "poda de partições" (partition pruning) nas consultas.
🚧 Problemas Enfrentados e 💡 Soluções Aplicadas¶
Durante o desenvolvimento do catálogo no BigQuery, vários desafios técnicos precisaram ser superados:
Problema 1: Trabalho Manual Massivo com TSV vs. Auto-descoberta
* O Problema: Inicialmente, algumas extrações de migração utilizavam arquivos TSV.GZ contendo dados brutos convertidos em Hexadecimal para prevenir corrupção. O problema é que, para o BigQuery ler arquivos TSV, era necessário definir o esquema (schema) de todas as centenas de tabelas manualmente no comando DDL, além de configurar delimitadores muito específicos (\x1F).
* A Solução: O pipeline abandonou o registro dos TSVs da migração em prol dos arquivos Parquet nativos. Com o Parquet, o script não precisava conhecer o esquema previamente; o BigQuery o absorveu automaticamente de dentro dos próprios arquivos.
Problema 2: Erro de Nomenclatura (Invalid table ID)
* O Problema: Durante a execução automatizada, a API do BigQuery retornou falhas como Invalid table ID "fonte=cloud_sql_historico".
* A Causa: O script de automação estava lendo a estrutura do bucket GCS de forma genérica e tentou usar uma pasta de marcação estrutural (fonte=cloud_sql_historico) como se fosse o nome lógico da tabela, quebrando regras de sintaxe que proíbem o caractere = no nome.
* A Solução: A lógica de descoberta (discover_tables_from_gcs) foi refatorada. Ela foi instruída a ignorar diretórios-pai e pular o nível de pasta do prefixo (tables_gcs_prefix), capturando apenas os nomes de pastas subsequentes (ex: Acao, Contato) para gerar identificadores limpos e mapeá-los para Datasets padronizados (ex: bronze_corp.Acao).
Problema 3: URIs Malformadas com Barras Duplas
* O Problema: Em testes de simulação (dry-run), os logs registraram caminhos de URI inválidos sendo enviados ao BigQuery, com barras duplas: gs://infoescola-datalake/bronze/fonte=cloud_sql_historico//TipoCabine/*.parquet.
* A Causa: Variáveis de configuração no arquivo settings.py já terminavam com barras, e o script concatenava uma nova barra adicional em tempo de execução.
* A Solução: Foi injetada a instrução de sanitização .rstrip('/') nas variáveis antes de montar as strings. A formatação do caminho foi centralizada e finalizada com o wildcard exato (/*.parquet), assegurando que o BigQuery recebesse um URI perfeitamente limpo.
Problema 4: Localização Geográfica dos Dados (Data Residency)
* O Problema: Caso os Datasets virtuais no BigQuery fossem criados de forma puramente automática sem parâmetros de localização, eles poderiam ser gerados numa região de nuvem incorreta (ex: EUA), gerando atrito para ler arquivos que estivessem salvos num bucket sul-americano.
* A Solução: O script foi ajustado para tratar exceções NotFound. Se o Dataset não existir, o script não apenas o cria, mas injeta explicitamente o atributo da região (dataset.location = "southamerica-east1" ou "US"), garantindo conformidade geográfica entre os metadados do BigQuery e o armazenamento físico do GCS.
🎯 Resumo da Fase¶
A "ingestão" no BigQuery consolidou-se em uma etapa ágil e moderna de mapeamento de Data Lake. Essa estratégia provou que é possível construir um motor de consulta massivo sobre dados brutos em poucos minutos, delegando ao formato Parquet a responsabilidade pelos tipos de dados e ao Python a automação total, mantendo a camada Bronze descentralizada e imutável.