top of page

Baixe grátis nossos e-books

Explore o mundo da Engenharia de Software e Data de forma mais eficiente e acessível com nossos eBooks!

  • Foto do escritorJP

Primeiros passos com DBT - Data Build Tool


O DBT tem sido utilizado por muitas empresas na área de Dados e acredito que podemos extrair bons insights neste post sobre ele. Esse vai ser um post prático mostrando como o DBT funciona e espero que vocês gostem.





O que é DBT?


DBT significa Data Build Tool e permite que equipes transformem os dados já carregados em seu warehouse através de operações de DML como um simples Select. DBT representa o T no processo de ELT, ou seja, ele não trabalha para extrair e carregar dados mas sim, para transformá-los.


Passo 1: Criando o projeto DBT


Agora, assumimos que o DBT já esteja instalado, mas se não estiver, recomendo consultar este link para mais informações.


Após a instalado, você pode criar um novo projeto usando CLI ou pode clonar este projeto do repositório DBT no Github.


Aqui para este post, vamos usar o modo CLI para criar nosso projeto e também para concluir as próximas etapas. Para criar um novo projeto, execute o comando abaixo no seu terminal.

dbt init

Depois de executar o comando acima, você precisa digitar o nome do projeto e qual warehouse ou banco de dados você vai usar conforme a imagem abaixo.


Para este post, vamos usar o adaptador do postgres. É muito importante que você tenha o banco de dados postgres já instalado ou você pode criar uma imagem postgres usando o docker.


Sobre os adaptadores, o DBT suporta vários deles e você pode conferir aqui.


Criei uma estrutura de tabela e também carreguei os dados simulando dados de uma plataforma de vídeo chamada wetube e vamos utilizá-los para entender como o DBT funciona. Acompanhe a estrutura:



Passo 2: Estrutura e mais sobre DBT


Após executar o comando dbt init para criar o projeto, uma estrutura de pastas e arquivos abaixo será criada.

Não vou falar sobre todos os diretórios do projeto, mas gostaria de focar em dois deles.



Sources


Antes de falarmos sobre os dois diretórios, vamos falar sobre os Sources, são basicamente os dados já carregados em seu warehouse. No processo DBT, as fontes têm o mesmo significado de dados brutos.


Não há pastas que representem dados Sources para este projeto, mas você precisa saber sobre este termo pois vamos configurar tabelas já criadas como Sources para as próximas seções.


Seeds


Seeds é um diretório que oferece um mecanismo interessante e útil para carregar dados estáticos em seu warehouse por meio de arquivos CSV. Se você deseja carregar esses dados, você precisa criar um arquivo CSV neste diretório e executar o comando abaixo.

dbt seed

Para cada campo no arquivo CSV, o DBT irá inferir os tipos e criará tabelas e suas colunas no warehouse ou banco de dados.


Models


O DBT funciona com o paradigma de Model, a ideia principal é que você pode criar modelos através da transformações utilizando instruções SQL baseadas em fontes de tabelas ou modelos existentes


Cada arquivo SQL localizado na pasta de model criará um modelo em seu warehouse ou banco de dados quando o comando abaixo for executado.

dbt run

Lembre-se que um modelo pode ser criado através de uma fonte ou outro modelo e não se preocupe com isso, vou mostrar mais detalhes sobre isso.


Passo 3: Configurando a configuração com o banco de dados


Com o projeto já criado, precisamos configurar a conexão com o banco de dados e aqui neste post vamos usar o postgres como banco de dados.


Depois de inicializar o projeto, vários arquivos são criados e um deles é chamado de profiles.yml.


profiles.yml é o arquivo é responsável por controlar os diferentes perfis/profiles para as diferentes conexões com os bancos de dados, como ambiente de desenvolvimento e produção. Se você notou, não podemos ver este arquivo na imagem acima porque este arquivo é criado fora do projeto para evitar credenciais que sejam confidenciais. Você pode encontrar esse arquivo no diretório ~/.dbt/.



Se você observar, temos um perfil chamado dbt_blog e um destino chamado dev, por padrão, o destino refere-se a dev com as configurações de conexão do banco de dados. Além disso, é possível criar um ou mais perfis e alvos(target), permitindo trabalhar com diferentes ambientes.


Outro detalhe importante é que o perfil dbt_blog deve ser especificado no arquivo dbt_project.yml como um perfil padrão. Nas próximas seções, discutiremos o que é e como o arquivo dbt_project.yml funciona.



Passo 4: Criando o arquivo dbt_project.yml


Todo projeto DBT possui um arquivo dbt_project.yml, você pode configurar informações como nome do projeto, diretórios, perfis e tipo de materialização.


name: 'dbt_blog'
version: '1.0.0'
config-version: 2
profile: 'dbt_blog'

model-paths: ["models"]
analysis-paths: ["analyses"]
test-paths: ["tests"]
seed-paths: ["seeds"]
macro-paths: ["macros"]
snapshot-paths: ["snapshots"]

target-path: "target"  # directory which will store compiled SQL files
clean-targets:         # directories to be removed by `dbt clean`
  - "target"
  - "dbt_packages"

models:
  dbt_blog:
    # Config indicated by + and applies to all files under models/example/
    mart:
      +materialized: table

Observe que o campo de profile foi configurado como o mesmo profile especificado no arquivo profiles.yml e outro detalhe importante é sobre o campo materialized. Aqui foi configurado como um valor table, mas por padrão, é uma view.


O campo materialized permite que você crie modelos como uma tabela ou view em cada execução. Existem outros tipos de materialização, mas não vamos discutir aqui e eu recomendo ver a documentação do dbt.



Passo 5: Criando nosso primeiro modelo


Criando os primeiros arquivos


Vamos mudar um pouco e vamos criar uma subpasta no diretório do model chamada mart e dentro desta pasta vamos criar nossos arquivos .SQL e também outro arquivo importante que ainda não discutimos chamado schema.yml.


Criando o arquivo schema


Os arquivos de schema são usados ​​para mapear fontes e documentar modelos como o nome do modelo, colunas e muito mais. Agora você pode criar um arquivo chamado schema.yml e preencher com as informações abaixo.


version: 2

sources:
  - name: wetube
    tables:
      - name: account
      - name: city
      - name: state
      - name: channel
      - name: channel_subs
      - name: video
      - name: video_like
      - name: user_address

models:
  - name: number_of_subs_by_channel
    description: "Number of subscribers by channel"
    columns:
      - name: id_channel
        description: "Channel's ID"
        tests:
          - not_null
      - name: channel
        description: "Channel's Name"
        tests:
          - not_null
      - name: num_of_subs
        description: "Number of Subs"
        tests:
          - not_null

Sources: No campo source você pode incluir tabelas do seu warehouse ou banco de dados que serão utilizadas na criação do modelo.


models: No campo models você pode incluir o nome do modelo, colunas e suas descrições


Criando um modelo


Esta parte é onde podemos criar scripts .SQL que resultarão em nosso primeiro modelo.


Para o primeiro modelo, vamos criar uma instrução SQL para representar um modelo que podemos ver os números de inscritos do canal. Vamos criar um arquivo chamado number_of_subs_by_channel.sql e preenchê-lo com os scripts abaixo.


with source_channel as (
    select * from
        {{ source('wetube', 'channel') }}
),

source_channel_subs as (
    select * from
        {{ source('wetube','channel_subs') }}
),

number_of_subs_by_channel as (
    select
        source_channel.id_channel,
        source_channel.name,
        count(source_channel_subs.id_subscriber) num_subs
    from source_channel_subs
       inner join source_channel using (id_channel)
    group by 1, 2
)

select * from number_of_subs_by_channel

Entendendo o modelo

  • Observe que temos vários scripts separados por expressão de tabela comum (CTE) que se torna útil para entender o código.


  • O DBT permite usar o template Jinja {{ }} trazendo uma maior flexibilidade ao nosso código.


  • O uso da palavra-chave source dentro do modelo Jinja significa que estamos nos referindo a tabelas de origem. Para referenciar um modelo, você precisa usar a palavra-chave ref.


  • A última instrução SELECT baseada nas tabelas de origem (source) irá gerar o modelo (model) como tabela no banco de dados.



Executando o nosso primeiro modelo


Execute o comando abaixo para criar nosso primeiro modelo baseado nos arquivos anteriores.

dbt run

Saída


Criando um novo modelo


Imagine que precisamos criar um novo modelo contendo as informações da conta e seus canais. Vamos voltar ao arquivo schema.yml para adicionar esse novo modelo.


- name: account_information
  description: "Model containing account information and it's channels"
  columns:
    - name: id_account
      description: "Account ID"
      tests:
        - not_null
    - name: first_name
      description: "First name of user's account"
      tests:
        - not_null
    - name: last_name
      description: "Last name of user's account"
      tests:
        - not_null
    - name: email
      description: "Account's email"
      tests:
        - not_null
    - name: city_name
      description: "city's name"
      tests:
        - not_null
    - name: state_name
      description: "state's name"
      tests:
        - not_null
    - name: id_channel
      description: "channel's Id"
      tests:
        - not_null
    - name: channel_name
      description: "channel's name"
      tests:
        - not_null
    - name: channel_creation
      description: "Date of creation name"
      tests:
        - not_null

Agora, vamos criar um novo arquivo SQL e nomeá-lo como account_information.sql e adicionar os scripts abaixo:

with source_channel as (
    select * from
        {{ source('wetube', 'channel') }}
),

source_city as (
    select * from
        {{ source('wetube','city') }}
),

source_state as (
    select * from
        {{ source('wetube','state') }}
),

source_user_address as (
    select * from
        {{ source('wetube','user_address') }}
),

source_account as (
    select * from
        {{ source('wetube','account') }}
),

account_info as (
    select
        account.id_user as id_account,
        account.first_name,
        account.last_name,
        account.email,
        city.name as city_name,
        state.name as state_name,
        channel.id_channel,
        channel.name as channel,
        channel.creation_date as channel_creation
    FROM source_account account
       inner join source_channel channel on (channel.id_account = account.id_user)
       inner join source_user_address user_address using (id_user)
       inner join source_state state using (id_state)
       inner join source_city city using (id_city)
)

select * from account_info

Criando nosso último modelo


Para o nosso último modelo, vamos criar um modelo sobre quantas curtidas tem um vídeo. Vamos alterar novamente o schema.yml para descrever e documentar nosso futuro e último modelo.


- name: total_likes_by_video
  description: "Model containing total of likes by video"
  columns:
    - name: id_channel
      description: "Channel's Id"
      tests:
        - not_null
    - name: channel
      description: "Channel's name"
      tests:
        - not_null
    - name: id_video
      description: "Video's Id"
      tests:
        - not_null
    - name: title
      description: "Video's Title"
      tests:
        - not_null
    - name: total_likes
      description: "Total of likes"
      tests:
        - not_null

Crie um arquivo chamado total_likes_by_video.sql e coloque o código abaixo:


with source_video as (
    select * from
        {{ source('wetube','video') }}
),

source_video_like as (
    select * from
        {{ source('wetube','video_like') }}
),

source_account_info as (
    select * from
        {{ ref('account_information') }}
),

source_total_like_by_video as (

    select source_account_info.id_channel, source_account_info.channel,
        source_video.id_video, source_video.title, count(*) as total_likes
    FROM source_video_like
        inner join source_video using (id_video)
        inner join source_account_info using (id_channel)
    GROUP BY source_account_info.id_channel,
             source_account_info.channel,
             source_video.id_video,
             source_video.title
    ORDER BY  total_likes DESC
)

select * from source_total_like_by_video

Executando novamente


Após a criação dos arquivos, vamos executar DBT novamente para criar os novos modelos

dbt run

Saída



Os modelos foram criados no banco de dados e você pode executar instruções select diretamente em seu banco de dados para verificá-lo. Perceba que além dos modelos criados, você pode notar as demais tabelas que foram mapeadas no arquivo schema.yml e que já existiam na estrutura do banco inicial. Lembre-se do mecanismo de criar tabelas estáticas através do diretório Seeds, pode ser uma boa escolha para uma carga inicial.



Modelo: account_information



Modelo: number_of_subs_by_channel



Modelo: total_likes_by_video



Passo 6: DBT Docs


Documentação


Depois de gerados nossos modelos, agora vamos gerar documentos com base nestes. O DBT gera uma documentação completa sobre modelos (models), sources e suas colunas, através de uma página da web.


Gerando as docs

dbt docs generate

Disponibilizando as docs no servidor Web


Após a geração dos documentos, você pode executar o comando abaixo no seu terminal para iniciar um servidor da Web na porta 8080 e consultar a documentação localmente utilizando o seu navegador. Caso o navegador não abra automaticamente, digite o seguinte endereço localhost:8080 no seu navegador.

dbt docs serve





Lineage


Outro detalhe sobre a documentação é que você pode ver através de um Lineage os modelos e suas dependências.





Código no Github


Você pode conferir esse código na nossa página do Github.


Curtiu? Eu espero que tenha gostado!



bottom of page