Para obter os arquivos das Demonstrações Contábeis, identifiquei que o servidor FTP da ANS organiza os arquivos em subdiretórios por ano (ex: /2024/, /2025/).
Algoritmo de Extração:
- O sistema acessa a raiz do diretório FTP público.
- Identifica as pastas dos anos mais recentes (ano atual e anterior).
- Navega dentro dessas pastas para listar os arquivos
.zipdisponíveis. - Filtra e ordena os arquivos para selecionar apenas os referentes aos últimos 3 trimestres disponíveis.
Trade-off Técnico (Jsoup vs API Rest): Como a ANS não fornece uma API REST documentada para listagem direta desses arquivos históricos, optei por utilizar a biblioteca Jsoup para fazer o parsing do HTML do diretório de arquivos.
- Pró: Solução leve e resiliente a mudanças simples de layout.
- Contra: Se a ANS mudar radicalmente a estrutura do HTML (ex: para uma SPA em React), o crawler precisará de manutenção.
- Decisão: Processamento via Streaming (Pipeline sem armazenamento intermediário em disco).
- Justificativa: Optei por não salvar os arquivos
.zipno disco antes de processar.
O sistema baixa, descompacta, lê, filtra e escreve no arquivo final em uma única passagem de dados (Single Pass).- Ganho de I/O: Evita escritas e leituras desnecessárias no disco rígido.
- Ganho de Memória: Processa linha a linha, permitindo que a aplicação rode em servidores com pouca RAM (ex: 512MB) sem travar,
mesmo processando gigabytes de dados.
- Observação: Embora a especificação de arquivos antigos sugerisse
ISO-8859-1,
a análise empírica dos dados atuais mostrou que o encoding correto éUTF-8.
O parser foi configurado explicitamente paraUTF-8para garantir a legibilidade dos termos acentuados
(ex: "ASSISTÊNCIA").
- Desafio: Associar os dados financeiros (milhões de linhas) aos dados cadastrais das operadoras (Razão Social e CNPJ) sem degradar a performance.
- Decisão: Implementação de um Hash Join em Memória.
- Justificativa: * O arquivo de cadastro de operadoras (Cadop) é relativamente pequeno (~1.000 a 2.000 registros), cabendo confortavelmente na memória RAM.
- Carregamos esses dados em um
HashMap<RegistroANS, OperadoraDTO>. - Durante o processamento do arquivo financeiro (gigante), a busca pelos dados da operadora ocorre em tempo constante O(1).
- Trade-off: Essa abordagem consome um pouco mais de memória RAM inicial para carregar o mapa, mas evita milhões de consultas ao Banco de Dados (N+1 problem) ou leituras de disco repetitivas, reduzindo o tempo total de execução drasticamente.
- Carregamos esses dados em um
- Problema: Instabilidade e bloqueios de segurança (WAF) frequentes no site da ANS (
gov.br)
impedem o download automatizado do cadastro de operadoras. - Solução: Implementação de um padrão de Fallback.
- O sistema tenta baixar a versão mais recente da API da ANS.
- Em caso de falha ou bloqueio, o sistema comuta automaticamente para um arquivo local (
relatorio-cadop.csv) embarcado no projeto.
- Justificativa: Garante que a aplicação continue funcionando em ambientes offline ou sob restrições de rede, priorizando a disponibilidade do serviço.
-
Carga em Lote (Batch Insert): Implementação via
JdbcTemplatepara inserção de dados em blocos de 500 registros.- Justificativa: Evita o overhead de milhares de conexões/transações individuais, otimizando o throughput de escrita no MySQL.
-
Fallback de Dados: Sistema híbrido que alterna entre download em tempo real e cache local (
relatorio-cadop.csv) para garantir a execução do ETL mesmo em cenários de indisponibilidade da fonte governamental. -
Tecnologias e Bibliotecas:
-
Spring JDBC (JdbcTemplate): Escolhido para a camada de persistência em lote (Batch Inserts)
devido à sua menor sobrecarga de memória comparado ao Hibernate/JPA, essencial para processar grandes volumes de dados ETL. -
OpenCSV: Utilizado para leitura e escrita streamada de arquivos,
garantindo o tratamento correto de caracteres de escape e delimitadores (RFC 4180).
- Objetivo: Identificar as operadoras com maiores gastos em "Eventos de Assistência a Saúde".
- Otimização: Uso de índices compostos e funções de agregação (
SUM) para performance em grandes volumes.
Este projeto consiste em um pipeline de dados (ETL) que realiza o web scraping de dados públicos da ANS (Agência Nacional de Saúde Suplementar), processa grandes volumes de arquivos ZIP/CSV e os consolida em um banco de dados relacional para análise.
- Java 25: Versão mais recente para aproveitar as últimas melhorias da JVM.
- Spring Boot 3.4.x: Core do projeto.
- Spring JDBC (JdbcTemplate): Persistência de alta performance com Batch Inserts.
- MySQL 8.0: Armazenamento relacional dos dados.
- Thymeleaf & Bootstrap 5: Camada de visualização (Frontend SSR).
- Jsoup: Web scraping e navegação no portal da ANS.
- OpenCSV: Processamento eficiente de streams de arquivos CSV.
-
Clone o repositório:
git clone [https://github.com/mauricioffdev/java-ans-etl-pipeline.git](https://github.com/mauricioffdev/java-ans-etl-pipeline.git)
-
Configuração do Banco:
- No MySQL, execute:
CREATE DATABASE intuitive_db; - O arquivo
src/main/resources/schema.sqlcriará a tabela automaticamente na primeira execução.
- No MySQL, execute:
-
Configuração da Aplicação:
- Acesse
src/main/resources/application.propertiese insira suas credenciais locais do MySQL.
- Acesse
-
Execução:
- Via IDE (IntelliJ) ou terminal:
mvn spring-boot:run. - Acesse o Dashboard em:
http://localhost:8080.
- Via IDE (IntelliJ) ou terminal:
- Performance: Optou-se por não utilizar Hibernate/JPA para a carga de dados devido ao overhead de memória.
O uso deJdbcTemplatecombatchUpdatepermitiu processar milhares de registros em segundos. - Resiliência: O sistema implementa uma estratégia de fallback: caso o crawler não consiga acessar o site da ANS (instabilidade do portal), ele processa automaticamente o arquivo
relatorio-cadop.csvlocal.
Mauricio Filadelfo Filho
https://github.com/mauricioffdev
https://www.linkedin.com/in/mauriciofiladelfofilho/