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:kanalsadece 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.ymlham 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
stg_siparislerstaging modelini yaz,sources.yml’defreshnessverelationshipstesti ekle.dbt source freshnessçalıştır, tüm source’ların güncel olduğunu doğrula.tests/assert_toplam_tutar_pozitif.sqlsingular testi yaz,dbt testçalıştır.- Her staging modeline ve sütununa
descriptionekle.