Resolver os problemas propostos pelo desafio utilizando uma arquitetura simples, resiliente e escalável.
Por existir a possibilidade de uma relação 1:n entre a entidade usuário
e a entidade endereço
, decidi modelar os dados em duas tabelas, uma para usuários e outra para endereços. Ao alterar a modelagem dos dados, as tabelas ficam na Terceira Forma Normal, melhorando a estrutura do banco de dados.
![](https://private-user-images.githubusercontent.com/62671380/327290725-3f4890f5-b14f-4538-8fa8-1319b8972919.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkxNTY4MTgsIm5iZiI6MTczOTE1NjUxOCwicGF0aCI6Ii82MjY3MTM4MC8zMjcyOTA3MjUtM2Y0ODkwZjUtYjE0Zi00NTM4LThmYTgtMTMxOWI4OTcyOTE5LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMTAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjEwVDAzMDE1OFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWM5MWZkMWNhMDM4NjVlZWMyMWM2ZjU4OGY1MzdjMmQyNzBjZjY3YWQ5NTQyNTEwYWNiMGJmNWFlZDdiZDVhOWImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.c8HYde3Ck8RSx7rXWaZBimORAv4qCNyOi7C3Vkl5QD4)
-
Docker: Conteinerização
-
Airflow: Orquestração
-
Postgres: Banco de Dados
-
PgAdmin: Interface gráfica/administrador do banco de dados
-
Metabase: Dashboard
Todos os serviços utilizados no desafio estão dockerizados, garantindo reprodutibilidade e escalabilidade. O ambiente é simples e está dividido em dois elementos principais: o banco de dados e o orquestrador. A divisão dos ambientes foi feita através dos arquivos docker-compose.yaml
, o primeiro arquivo, referente ao ambiente do Airflow, centraliza todos os serviços necessários para a sua execução (banco de dados, variáveis de ambiente, requirements, webserver e etc) e o segundo, referente ao ambiente do Postgres, centraliza os serviços necessários para a sua execução além de criar as conexões necessárias entre o banco, o PgAdmin e o Metabase.
Uma observação importante é que precisa haver uma conexão ativa entre os dois docker composes, para que o Airflow consiga se comunicar com o banco Postgres e vice-versa. Para isso, foi criado um arquivo .env
contendo as variáveis de ambiente necessárias para o Airflow se comunicar com o Postgres, além da criação da conexão entre o contêiner do banco e o contêiner do worker do Airflow (que é responsável por executar as DAGs).
Exemplo do arquivo .env
:
AIRFLOW_UID=501
PG_HOST=pgdatabase
PG_USER=root
PG_PASSWORD=root
PG_PORT=5432
PG_DATABASE=capim
Exemplo da conexão no arquivo postgres/docker-compose.yaml
:
networks:
airflow:
external:
name: airflow_default
O airflow executa a DAG com o nome de CompleteIngestionDag
, que está no arquivo ./airflow/data_ingestion_local.py
. Ela possui 4 tasks que fazem o processo de extração -> validação -> criação das tabelas -> carregamento dos dados no banco. Os dados brutos são extraídos da URL e salvos em um arquivo data.json
, em seguida passam pela validação feita através do pydantic
, que verifica o tipo dos dados, o schema e outras condições específicas (como o formato dos dados da coluna cep
, por exemplo). Caso passem na validação, as tabelas são criadas -- caso não existam -- e os dados são carregados.
Visando resolver o problema do desafio, uma lógica foi criada para impossibilitar o carregamento de dados duplicados no banco. O fluxo confere a existência da chave única na tabela de usuários e a existência do conjunto cep ~ logradouro ~ número
na tabela de endereços, para todas as observações, e só insere os novos dados se eles forem únicos e se não existirem previamente no banco. Esse processo garante a integridade e a atomicidade dos dados.
![Captura de Tela 2024-05-01 às 23 42 03](https://private-user-images.githubusercontent.com/62671380/327295851-70dc31c9-07ac-4ef5-a6a4-f17ffa0af37f.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkxNTY4MTgsIm5iZiI6MTczOTE1NjUxOCwicGF0aCI6Ii82MjY3MTM4MC8zMjcyOTU4NTEtNzBkYzMxYzktMDdhYy00ZWY1LWE2YTQtZjE3ZmZhMGFmMzdmLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMTAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjEwVDAzMDE1OFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTEyMzIzOGEzY2Q3ZGExOTI4ZTdkNjZmNmEwMjJhMGNlN2RhMzM2OTA5ZTBiZjA3NmM3MTQ1OGI0ZjU1MjJkYmUmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.H8iSxkG5rqQ_icCbwdS2xFrDsaB-4KY0bI8DmTrAYEU)
![Captura de Tela 2024-05-01 às 23 47 55](https://private-user-images.githubusercontent.com/62671380/327296712-690561e8-02ed-417e-902c-89608a76b334.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkxNTY4MTgsIm5iZiI6MTczOTE1NjUxOCwicGF0aCI6Ii82MjY3MTM4MC8zMjcyOTY3MTItNjkwNTYxZTgtMDJlZC00MTdlLTkwMmMtODk2MDhhNzZiMzM0LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMTAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjEwVDAzMDE1OFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTBiOThiZWM4ZWRjNjQ5NjJmMzEwOTMxNjgwZjNhNjM2Y2U3MTgxM2JhMDI0ODE3NmQ3ODk2NzQzOTM1YWQwNmImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.Zl9p4Wy9OQgAFU3El7xNl7tjVNniJaVHwEBWg_WLPLk)
![Captura de Tela 2024-05-01 às 23 48 04](https://private-user-images.githubusercontent.com/62671380/327296705-c973a227-2949-4a9e-8576-440858d5bb12.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkxNTY4MTgsIm5iZiI6MTczOTE1NjUxOCwicGF0aCI6Ii82MjY3MTM4MC8zMjcyOTY3MDUtYzk3M2EyMjctMjk0OS00YTllLTg1NzYtNDQwODU4ZDViYjEyLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMTAlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjEwVDAzMDE1OFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTZhOTg2MjIxOTc3ZDE1ZDc0Yjc4ODI5MTVhZDkzNTI5NjFhNWJjNWFiNDY2MDhmNjdkMTRiYzdkMzNjMWM4NDAmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.kgyO5HziJrmF7BgyQouiLpSHJcwBp08JjKqfV7XdIOM)
- Clone o repositório:
git clone https://github.com/arthurfg/desafio-data-engineer.git
- Navege até o repo:
cd </path/to/repo>
- Crie um arquivo
.env
com essas variáveis:
AIRFLOW_UID=<seu UID>
PG_HOST=pgdatabase
PG_USER=root
PG_PASSWORD=root
PG_PORT=5432
PG_DATABASE=capim
Caso use linux/mac, insira o ID que resulta desse comando na variável de ambiente AIRFLOW_UID
:
echo "$(id -u)"
Caso use outro sistema operacional use AIRFLOW_UID=50000
.
- Navege até o diretório
./airflow
:
cd airflow
- Inicialize o airflow:
docker compose up airflow-init
- Rode o docker compose:
docker compose up
- Navege até o diretório
./postgres
:
cd postgres
- Rode o docker compose:
docker compose up
Após todos os contêiners estarem ativos e rodando, vá até o http://localhost:8080/
, digite o usuário airflow
e a senha airflow
e rode a DAG CompleteIngestionDag
.