Modül 5 · Analitik Mühendisliği (dbt) · ⏱ 7 dk

Sources, models, seeds, tests, docs

dbt sources-models-seeds-tests

Bu derste neler öğreneceksin

  • Source tanımlar
  • Seed verisi ekler
  • Test yazar + dökümante eder

Staging Katmanı: Ham Veriyi Normalize Et

Production’da ham veri bir blob’dur: şema karışık, sütun isimleri tutarsız (customer_id / customerId / cust_id hepsi aynı şey), tarihler string, NULL’lar her yerde. dbt’de ilk iş bunları staging katmanında normalize etmek: 1 source = 1 staging model, sütunları temizle, tipleri düzelt.

models/staging/stg_siparisler.sql:

WITH source AS (
  SELECT * FROM {{ source('raw', 'siparisler') }}
),
renamed AS (
  SELECT
    CAST(siparis_id AS INT64)              AS siparis_id,
    LOWER(TRIM(musteri_id))                AS musteri_id,
    CAST(siparis_tarihi AS TIMESTAMP)      AS siparis_tarihi,
    CAST(toplam_tutar AS NUMERIC)          AS toplam_tutar,
    CAST(indirim AS NUMERIC)               AS indirim,
    UPPER(TRIM(kanal))                     AS kanal
  FROM source
  WHERE siparis_id IS NOT NULL
)
SELECT * FROM renamed

Bu model tek bir şey yapar: ham tabloyu al, sütunları temizle, downstream modeller bu temiz hali kullanır. Bir kez normalize et, elli yerde aynı CAST yazma.

Sources: Single Source of Truth

Ham tablonun adresi (proje.dataset.tablo) her modele dağılırsa, bir gün şema adı değiştiğinde cehennem olur. sources.yml ile tek yerde tanımla:

version: 2

sources:
  - name: raw
    database: my-limonata-lab
    schema: raw_data
    loaded_at_field: _loaded_at
    freshness:
      warn_after: { count: 6, period: hour }
      error_after: { count: 24, period: hour }
    tables:
      - name: siparisler
        description: "Tüm kanallardan gelen sipariş kayıtları (POS, e-ticaret, telefon)"
        columns:
          - name: siparis_id
            description: "Benzersiz sipariş kimliği (POS: PREFIX-YYYYMMDD-NNNN)"
            tests:
              - unique
              - not_null
          - name: musteri_id
            tests:
              - not_null
              - relationships:
                  to: source('raw', 'musteriler')
                  field: musteri_id

Freshness özelliği önemli: dbt “kaynak tablo ne kadar eski olabilir?” diye sorar. Eğer 24 saat geçtiyse ve hâlâ güncellenmiyorsa dbt source freshness hata verer — pipeline bozulmuş demek.

relationships testi: musteri_id foreign key doğruluğu için otomatik kontrol. Siparişteki müşteri gerçekten musteriler tablosunda var mı?

Tests: Veri Kalitesinin Bel Kemiği

dbt iki test kategorisi sunar:

1. Schema (generic) tests — yml’de tanımlı

Built-in testler:

  • unique: sütundaki değerler tekrarsız.
  • not_null: NULL yok.
  • accepted_values: sütun sadece izinli değerlerden biri (ör: kanal sadece POS/ECOM/PHONE).
  • relationships: foreign key doğruluğu.

Custom generic testler yazılabilir (paket olarak). Örnek dbt_expectations:

columns:
  - name: toplam_tutar
    tests:
      - dbt_expectations.expect_column_values_to_be_between:
          min_value: 0
          max_value: 10000
      - dbt_expectations.expect_column_values_to_not_match_regex:
          regex: ".*HATA.*"

2. Singular tests — tek SQL dosyası

tests/assert_gunluk_ciro_pozitif.sql:

SELECT siparis_gunu, net_ciro
FROM {{ ref('fct_gunluk_siparis') }}
WHERE net_ciro < 0

Herhangi bir satır dönerse FAIL. Genellikle “asla olmaması gereken” durumlar için yazılır.

Testleri Çalıştır

dbt test                          # tüm testler
dbt test --select stg_siparisler  # sadece bu modele bağlı
dbt test --select tag:kritik      # tag'li testler
dbt build                         # run + test (production için)

CI/CD’de dbt build exit code’unu kontrol et — FAIL varsa merge engellenir.

Seeds: Statik Boyut Tabloları

Boyut tabloları (ülke, ürün kategorisi, mağaza listesi) milyon satır değil, nadiren değişir. Bunları CSV olarak projede tut, dbt seed ile yükle.

seeds/dim_icecek_kategorileri.csv:

kategori_id,kategori_adi,ust_kategori_id
1,Klasik,NULL
2,Özel,NULL
3,Mevsim,NULL
11,Limonata Klasik,1
12,Nane Limonata,1
dbt seed --select dim_icecek_kategorileri

Kural: Seed sadece < 100K satır ve yavaş değişen veri için. Müşteri listesini seed yapma — warehouse’da zaten var.

Docs: Otomatik Veri Kataloğu

yml dosyalarına yazdığın description’lar dbt docs generate ile toplanır. Bir sonraki derste (dbt docs sitesi) detaylı göreceğiz. Şimdilik: her model ve her sütuna 1-2 cümlelik description yaz.

models/marts/schema.yml:

version: 2

models:
  - name: fct_gunluk_siparis
    description: "Her müşteri için günlük sipariş özeti (ciro, adet, kanal)"
    columns:
      - name: siparis_gunu
        description: "Sipariş tarihi (date, partition key)"
      - name: musteri_id
        description: "Müşteri kimliği (FK → dim_musteri)"
        tests:
          - not_null
          - relationships:
              to: ref('dim_musteri')
              field: musteri_id

Ne Öğrendik?

  • Staging katmanı ham veriyi normalize eder (1:1 source).
  • sources.yml ham tabloların adresini + freshness kurallarını merkezileştirir.
  • Generic tests (unique, not_null, accepted_values, relationships) + singular tests = veri kalitesi güvencesi.
  • dbt build = run + test + snapshot + seed; CI’da bu çalıştırılır.
  • Seeds küçük statik CSV’ler içindir; docs description’lardan otomatik katalog üretir.

Küçük Ödev

  1. stg_siparisler staging modelini yaz, sources.yml’de freshness ve relationships testi ekle.
  2. dbt source freshness çalıştır, tüm source’ların güncel olduğunu doğrula.
  3. tests/assert_toplam_tutar_pozitif.sql singular testi yaz, dbt test çalıştır.
  4. Her staging modeline ve sütununa description ekle.

Sıradaki

Macros (Jinja) + Packages: tekrar eden kodu soyutla →