</> dbt Analytics Engineering

0 / 16 section completed
Section 00

dbt Analytics Engineering dbt Delta Lake

Az analytics engineering a data engineering és a business intelligence metszéspontja: olyan disciplína, amely az adatok nyers forrásból történő megtisztításától kezdve az üzleti döntéstámogatásig terjedő teljes transzformációs láncot felügyeli. A dbt (data build tool) ennek a területnek az iparági standard eszköze, amely lehetővé teszi, hogy SQL-ben definiáljunk transzformációkat, adatminőségi teszteket és automatikus dokumentációt — mindezt szoftverfejlesztési最佳 gyakorlatok (version control, CI/CD, code review) mentén.

Miért fontos ez? A hagyományos data warehouse világban az ETL folyamatokat gyakran véletlenszerűen szétszórt SQL scriptek és stored procedure-k alkották, amelyeket nehéz volt tesztelni, dokumentálni és karbantartani. A dbt bevezeti a szoftverfejlesztés módszertanát az adattranszformációk világába: moduláris modellstruktúrát, automatikus függőségkezelést (DAG), és beépített tesztelési keretrendszert biztosít. Így a data engineer-ek és az analitikusok közös nyelven, közös eszközökkel dolgozhatnak.

Ebben a kurzusban a WebShop Pro e-kereskedelmi platform analytics layer-ét fogjuk felépíteni. A nyers rendelési, ügyfél- és termékadatokból kiindulva, három rétegen (staging, intermediate, mart) keresztül alakítunk ki üzleti-ready adatmodelleket. Megtanuljuk a schema tesztek írását, az incremental modellek optimalizált működését, a snapshot-ok használatát, és a macro-k segítségével történő kód-újrahasznosítást.

Tip: A dbt nem adatbetöltő eszköz (nem csatlakozik API-khoz vagy külső rendszerekhez) — a transzformációs rétegért felel. Az adatok betöltését külön ETL/ELT eszközök (pl. Fivetran, Airbyte) végzik, a dbt pedig a már betöltött nyers adatokat alakítja át elemzésre alkalmassá.

Tartalom

staging, intermediate, mart modellek, schema tests, incremental models, snapshots, macros

Projekt

WebShop Pro analytics layer: staging -> intermediate -> mart modellek

Szójegyzék

dbt · Materialization · Lineage

Section 01

dbt beállítása

A dbt beállítása két fő lépésből áll: a dbt-core telepítéséből és a profiles.yml konfigurációjából. A dbt-core a Python csomag, amely a parancssori eszközt és a futtatási motort biztosítja, míg a dbt-postgres (vagy más adapter) a cél adatbázissal való kommunikációért felel. A profiles.yml fájl tartalmazza az adatbázis-csatlakozási adatokat, és általában a ~/.dbt/ könyvtárban található — így nem kerül bele a projekt repository-ba, ami fontos biztonsági szempont.

Miért különválik a profiles.yml a projekt konfigurációjától? Mert így a fejlesztők különböző környezeteket (dev, staging, prod) használhatnak ugyanazzal a kódbázissal. A profiles.yml-ben definiált target határozza meg, hogy a dbt parancsok melyik adatbázis-sémára futnak, míg a dbt_project.yml a projekt-szintű beállításokat (model paths, materializációk) vezérli. A dbt init parancs interaktívan végigvezet a kezdeti beállításon, létrehozva a projekt skeleton-t.

A példában a webshop_analytics projektet inicializáljuk PostgreSQL cél-adatbázissal. A dev target a localhost-on futó webshop_pro adatbázis analytics sémájába irányít, 4 párhuzamos szállal (threads). A thread-ek száma befolyásolja, hogy hány modellt tud a dbt egyszerre futtatni — éles környezetben érdemes magasabbra (8-16) állítani, de fejlesztésnél a 4 elegendő.

Tip: Soha ne commit-old a profiles.yml-t a repository-ba! Használj .dbt/profiles.yml.tmpl sablonfájlt, amelyben a jelszók helyett helyőrzők vannak. CI/CD pipeline-ban környezeti változókból vagy secret manager-ből (pl. AWS Secrets Manager) töltsd ki a valós értékeket.

[1]
# Install dbt
pip install dbt-core dbt-postgres

# Initialize project
dbt init webshop_analytics

# profiles.yml
webshop_analytics:
  target: dev
  outputs:
    dev:
      type: postgres
      host: localhost
      user: admin
      password: secret
      dbname: webshop_pro
      schema: analytics
      threads: 4
Output:
dbt project initialized at /home/user/webshop_analytics
Profile configured for dev environment
Section 02

Projekt struktúra

A dbt projekt struktúra a konvenciókra épül: minden könyvtár egy jól definiált szerepet tölt be. A models/ könyvtár a legfontosabb — ide kerülnek az SQL transzformációs fájlok, amelyeket a dbt futtat. A tests/ könyvtár egyedi SQL teszteket tartalmaz, a macros/ újrahasználható Jinja sablonokat, a snapshots/ SCD Type 2 időutazó históriát, a seeds/ pedig CSV fájlokat, amelyek referenciatáblákként (pl. országkódok, kategória-mapping) tölthetők be.

A dbt_project.yml a projekt központi konfigurációs fájlja. Itt adjuk meg a projekt nevét, verzióját, a használni kívánt profilt (ami a profiles.yml-hez kapcsolódik), és a különböző könyvtárak elérési útját. A legfontosabb rész a models szekció, ahol rétegenként (staging, intermediate, marts) beállíthatjuk az alapértelmezett materializációt. A materializáció határozza meg, hogyan tárolja a dbt a modellt: view (virtuális nézet, nem foglal helyet), table (fizikai tábla, minden futáskor újraépül), vagy incremental (csak az új adatokat adja hozzá).

A példában a staging és intermediate rétegek view-ként, a marts pedig table-ként van materializálva. Ez egy bevált minta: a finomítási lépések (ahol gyakran változik a logika) view-ként működnek, míg a végső business-ready táblák fizikai táblaként, gyorsabb lekérdezhetőség érdekében. A +materialized jelölés azt jelenti, hogy az adott könyvtár összes modelljére érvényes a beállítás, hacsak egy adott modell felül nem írja.

Tip: Tartsd a projekt struktúrát konzisztensen — minden rétegnek saját alkönyvtára legyen a models/ alatt. Ne keverd a staging és mart modelleket egy mappában, mert a későbbi karbantartás és az új csapattagok onboarding-ja sokkal nehezebb lesz.

KönyvtárTartalom
models/SQL modellek (staging, intermediate, marts)
tests/Egyedi tesztek
macros/Újrahasználható SQL kód
snapshots/SCD Type 2 automatikus
seeds/CSV seed adatok
dbt_project.ymlProjekt konfiguráció
[2]
# dbt_project.yml
name: webshop_analytics
version: '1.0.0'
profile: webshop_analytics

model-paths: ['models']
test-paths: ['tests']
macro-paths: ['macros']
seed-paths: ['seeds']

models:
  webshop_analytics:
    staging:
      +materialized: view
    intermediate:
      +materialized: view
    marts:
      +materialized: table
Output:
Project structure:
models/
  staging/
  intermediate/
  marts/
tests/
macros/
seeds/
Section 03

Staging modellek

A staging réteg a nyers adatok első érintkezése a dbt modellezési folyamattal. Itt történik a forrásadatok tisztítása, átnevezése és alapvető szűrése — de semmilyen üzleti logika vagy aggregáció nem. A staging modellek a Medallion architektúra Bronze rétegének felelnek meg: egy-az-egyhez kapcsolatban állnak a forrástáblákkal, de a oszlopnevek már konzisztensek, az adattípusok helyesek, és az érvénytelen sorok kiszűrésre kerültek.

A példa kód egy klasszikus staging modellt mutat be. A CTE (Common Table Expression) struktúra két lépésre van osztva: először a source() függvénnyel olvassuk be a nyers adatokat (a source definíciót a következő szekcióban részletezzük), majd egy renamed CTE-ben végezzük a tisztítást. Az order_date oszlopot timestamp-é konvertáljuk és átnevezzük ordered_at-ra, a total_amount-ot amount-ra egyszerűsítjük, és létrehozunk egy is_cancelled boolean mezőt a status alapján. A where feltétel kiszűri a null státuszú sorokat.

Miért fontos, hogy a staging réteg „buta" legyen? Mert ha a nyers adatok strukturálása és az üzleti logika összekeveredik, akkor bármelyik réteg változása megbonthatja a másikat. A staging legyen egy megbízható, stabil alap, amelyre az intermediate és mart modellek épülhetnek. Ideális esetben egy staging modell módosítása ritka — a változások az üzleti logikát érintik, ami a magasabb rétegekben történik.

Tip: Használd konzisztensen a CTE struktúrát minden staging modellben (source, renamed, filtered). A konvenció követése miatt a csapattagok azonnal tudják, hol keresgéljenek. Kerüld a join-ok és aggregációkat a staging rétegben — azok az intermediate vagy mart szintre valók.

[3]
-- models/staging/stg_orders.sql
with source as (
    select * from {{ source('webshop', 'raw_orders') }}
),
renamed as (
    select
        order_id,
        customer_id,
        order_date::timestamp as ordered_at,
        total_amount as amount,
        status,
        case when status = 'cancelled' then true else false end as is_cancelled
    from source
    where status is not null
)
select * from renamed
Output:
$ dbt run --select stg_orders
OK created view model analytics.stg_orders [SELECT 1420]
Section 04

Source és ref

A source() és ref() függvények a dbt DAG (Directed Acyclic Graph) rendszerének alapkövei. A source() a külső forrástáblákra hivatkozik — azokra a nyers adatokra, amelyeket nem a dbt hoz létre, hanem egy külső ETL eszköz tölt be. A ref() pedig a projektben lévő más dbt modellekre hivatkozik, automatikusan felépítve a függőségi láncot. Amikor egy modell ref('stg_orders') hivatkozást tartalmaz, a dbt tudja, hogy előbb a stg_orders modellt kell lefuttatnia.

A sources.yml fájl nemcsak a forrástáblák elérhetőségét definiálja, hanem a freshness (frissesség) ellenőrzést is. A loaded_at_field megadja, melyik oszlop alapján mérjük az adatok frissességét, a warn_after és error_after pedig a küszöbértékeket. Ha a raw_orders tábla utolsó betöltése 12 órával ezelőtt történt, a dbt warningot ad; ha 24 órával, akkor hibát. Ez kritikus monitoring eszköz éles rendszerekben.

A forrásdefiníció és a ref rendszer együtt teszi lehetővé a dbt docs generate parancs által generált lineage diagramot. A DAG vizualizációban láthatóvá válik, hogy melyik modell melyikből származik, hol vannak szűk keresztmetszetek, és mi történik, ha egy forrástábla nem frissül. Ez a transzparencia az egyik legnagyobb előny a hagyományos SQL scriptekkel szemben.

Tip: Mindig definiáld a forrásokat sources.yml-ben ahelyett, hogy közvetlenül táblaneveket használnál a modellben. Így a dbt tudja követni a források frissességét, és ha a forrástábla neve vagy sémája változik, csak egy helyen (a sources.yml-ben) kell módosítanod.

[4]
-- models/sources.yml
version: 2
sources:
  - name: webshop
    schema: raw
    tables:
      - name: raw_orders
        loaded_at_field: loaded_at
        freshness:
          warn_after: {count: 12, period: hour}
          error_after: {count: 24, period: hour}
      - name: raw_products
      - name: raw_customers

-- Use in models:
select * from {{ source('webshop', 'raw_orders') }}
select * from {{ ref('stg_orders') }}
Output:
$ dbt source freshness
raw_orders: 2 hours ago (WARN)
raw_products: 30 min ago (PASS)
Section 05

Intermediate modellek

Az intermediate réteg a staging és a mart közötti híd: itt történik az adatok dúsítása join-okkal, az üzleti logika bevezetése és a komplex transzformációk. A Medallion architektúra Silver rétegének megfelelően az intermediate modellek már tisztított adatokkal dolgoznak (a staging-ből származókkal), és több forrásból vonják össze az információt. Ez az a szint, ahol a rendelések összekapcsolódnak az ügyfelekkel és termékekkel.

A példában az int_orders_enriched modell három staging modellt (stg_orders, stg_customers, stg_products) joinol össze. A ref() hivatkozások miatt a dbt automatikusan tudja, hogy előbb ezt a három modellt kell lefuttatnia. A where not o.is_cancelled feltétel kiszűri a visszamondott rendeléseket — ez már üzleti döntés, ami a staging-ben nem szerepelt. Az eredmény egy „széles" tábla, amely rendelésenként tartalmazza az ügyfél és termék adatait is.

Miért nem csináljuk ezt a mart rétegben? Mert az intermediate modell egy újrahasználható építőelem. Több mart modell is épülhet ugyanerre a dúsított adathalmazra: a havi bevételi riport éppúgy használja, mint az ügyfélszegmentációs modell. Ha a join-logika csak a mart-ban lenne, minden mart modellben duplikálva lenne, ami karbantartási rémálommá válna.

Tip: Ne légy mohó — ne hozz létre túl sok intermediate modellt. A jó Intermediate réteg a gyakran ismétlődő join-mintákat foglalja össze. Ha egy join csak egyetlen mart-ban használjuk, érdemes azt közvetlenül a mart modellbe tenni, külön intermediate fájl helyett.

[5]
-- models/intermediate/int_orders_enriched.sql
with orders as (
    select * from {{ ref('stg_orders') }}
),
customers as (
    select * from {{ ref('stg_customers') }}
),
products as (
    select * from {{ ref('stg_products') }}
)
select
    o.order_id,
    c.name as customer_name,
    c.city,
    c.segment,
    p.name as product_name,
    p.category,
    o.amount,
    o.ordered_at
from orders o
join customers c on o.customer_id = c.customer_id
join products p on o.product_id = p.product_id
where not o.is_cancelled
Output:
$ dbt run --select int_orders_enriched
OK created view model analytics.int_orders_enriched [SELECT 1380]
Section 06

Mart modellek

A mart réteg az analytics architektúra csúcsa: itt találhatók a business-ready aggregációk, dimenziók és fact táblák, amelyeket az elemzők, BI eszközök és döntéshozók közvetlenül használnak. A Medallion architektúra Gold rétegének megfelelően ezek a modellek fizikai táblákként (materialized: table) jönnek létre, biztosítva a gyors lekérdezhetőséget. A mart modellek nevükben gyakran követik a dim_ (dimenzió) és fct_ (fact) előtag konvenciót.

A példa egy klasszikus fact táblát mutat be: fct_monthly_revenue, amely az int_orders_enriched intermediate modellből épül. A date_trunc havi szintre aggregál, a count distinct egyedi rendeléseket és ügyfeleket számol, a sum a teljes bevételt, az avg pedig az átlagos rendelési értéket. A group by 1, 2, 3 a pozíció alapján hivatkozik a select oszlopokra — ez SQL-ben egy átlátható rövidítés.

A mart modellek kulcsfontosságú szabálya: egy modell egy üzleti entitást vagy metrikát képvisel. A fct_monthly_revenue a bevételről szól, a dim_customers az ügyfelekről. Ne keverj össze több különböző granularitást egy modellben — ha a havi és napi aggregációkra is szükség van, hozz létre két külön modellt. A tiszta, egyértelmű granularitás biztosítja, hogy a BI eszközök helyesen tudjanak joinolni és szűrni.

Tip: Nevezd el a mart modelleket úgy, hogy az üzleti felhasználók is megértsék. A fct_monthly_revenue egyértelmű, de a fct_agg_01 nem mondd semmit. Az oszlopoknál is használj beszédes neveket (revenue, order_count), és dokumentáld őket a models YML fájlban.

[6]
-- models/marts/fct_monthly_revenue.sql
with enriched as (
    select * from {{ ref('int_orders_enriched') }}
)
select
    date_trunc('month', ordered_at) as month,
    category,
    segment,
    count(distinct order_id) as order_count,
    count(distinct customer_name) as unique_customers,
    sum(amount) as revenue,
    avg(amount) as avg_order_value
from enriched
group by 1, 2, 3
order by 1, 2
Output:
$ dbt run --select fct_monthly_revenue
OK created TABLE analytics.fct_monthly_revenue [SELECT 48]
Section 07

Schema tesztek

A schema tesztek a dbt beépített adatminőségi ellenőrzései, amelyeket YAML fájlokban definiálunk. Négy alapvető teszttípus létezik: unique (az oszlop értékei egyediek), not_null (nincs hiányzó érték), accepted_values (az oszlop csak megadott értékeket vehet fel), és relationships (idegen kulcs integritás — az értéknek léteznie kell egy másik tábla megfelelő oszlopában). Ezek a tesztek SQL lekérdezésekké fordulnak, amelyek a hibás sorokat adják vissza — ha az eredményhalmaz üres, a teszt átment.

A példában az order_id oszlopra unique és not_null teszteket futtatunk (biztosítva, hogy minden rendelésnek legyen egyedi azonosítója), a customer_id-ra not_null és relationships tesztet (ellenőrzi, hogy minden ügyfél ID létezik a stg_customers táblában), a status-ra pedig accepted_values (csak a négy megengedett státuszérték egyike lehet). Ez a teszt-kombináció gyakorlatilag biztosítja az adatok referenciális integritását és az üzleti szabályok betartását.

A schema tesztek futtatása a dbt test paranccsal történik, amely a dbt run után érdemes lefuttatni. CI/CD pipeline-ban mindkettőt automatizálni kell: ha bármelyik teszt elbukik, a deployment nem folytatódhat. A teszteredmények a dbt docs-ban is megjelennek, így az adatok felhasználói láthatják, milyen minőségi garanciák vannak az adatokra nézve.

Tip: Definiálj teszteket minden kritikus oszlopra — legalább not_null az elsődleges kulcsokra és relationships az idegen kulcsokra. Ne várd meg, amíg egy üzleti felhasználó jelzi, hogy duplikált rendelésszámokat lát; a tesztek proaktívan védik az adatminőséget.

[7]
# models/staging/_stg_models__yml.yml
version: 2
models:
  - name: stg_orders
    columns:
      - name: order_id
        tests: [unique, not_null]
      - name: customer_id
        tests:
          - not_null
          - relationships:
              to: ref('stg_customers')
              field: customer_id
      - name: status
        tests:
          - accepted_values:
              values: ['pending', 'shipped', 'delivered', 'cancelled']
Output:
$ dbt test --select stg_orders
PASS: unique_stg_orders_order_id
PASS: not_null_stg_orders_customer_id
PASS: relationships_stg_orders_customer_id
4 of 4 tests passed
Section 08

Custom tesztek

A custom tesztek olyan SQL lekérdezések, amelyeket a dbt beépített schema tesztek kiegészítésére írunk. Míg a schema tesztek általános adatintegritást vizsgálnak (unique, not_null), a custom tesztek üzleti specifikus szabályokat ellenőriznek. A teszt SQL fájlnak olyan lekérdezést kell tartalmaznia, amely a hibás sorokat adja vissza — ha a lekérdezés üres eredményt ad, a teszt sikeres.

A példa két custom tesztet mutat be. Az assert_positive_revenue teszt ellenőrzi, hogy nincs-e negatív összeget tartalmazó rendelés (az amount oszlop nem lehet kisebb nullánál). Az assert_recent_orders teszt pedig azt validálja, hogy az elmúlt 7 napban történt-e legalább egy rendelés — ez egy úgynevezett „volume anomaly" teszt, amely észleli, ha váratlanul megszakadt az adatbetöltés. Ezek olyan feltételek, amelyeket a beépített tesztek nem tudnak ellenőrizni.

A custom tesztek a tests/ könyvtárba kerülnek, és a dbt test paranccsal együtt futnak a schema tesztekkel. A teszt neve a fájl nevéből származik (assert_positive_revenue.sql leszz assert_positive_revenue teszt). A ref() függvénnyel hivatkozhatsz bármelyik modellre, így a tesztek a teljes DAG-ból származó adatokat is vizsgálhatják.

Tip: Írj custom tesztet minden kritikus üzleti szabályra — pl. „a szállítási dátum nem lehet korábbi, mint a rendelés dátuma" vagy „az engedmény nem lehet nagyobb, mint a rendelés összege". Ezek a tesztek az üzleti logika „élő dokumentációjaként" is szolgálnak.

[8]
-- tests/assert_positive_revenue.sql
select order_id
from {{ ref('stg_orders') }}
where amount < 0

-- tests/assert_recent_orders.sql  
select count(*) as cnt
from {{ ref('stg_orders') }}
where ordered_at >= dateadd('day', -7, current_timestamp)
having count(*) < 1
Output:
$ dbt test
PASS: assert_positive_revenue (0 failures)
PASS: assert_recent_orders (0 failures)
Section 09

Incremental modellek

Az incremental modellek a dbt teljesítményoptimalizálásának kulcsa: ahelyett, hogy minden futáskor az összes historikus adatot újra feldolgoznák, csak az új vagy módosított sorokat adják hozzá a már meglévő táblához. Ez különösen fontos nagy adatmennyiség esetén — ha millió soros rendeléstörténetünk van, felesleges minden nap újra feldolgozni az összes múltbeli rendelést, amikor csak a napi újak érkeztek.

A példában a config(materialized='incremental', unique_key='order_id') beállítás mondja meg a dbt-nek, hogy ez egy incremental modell, és az order_id alapján azonosítja az egyedi sorokat. Az is_incremental() Jinja függvény feltételes logikát biztosít: az első futáskor (amikor még nincs tábla) az összes adatot betölti, a későbbi futásokon pedig csak azokat, amelyek ordered_at értéke nagyobb, mint a táblában lévő maximum. A {{ this }} a jelenlegi modell táblanév-referenciáját helyettesíti.

A unique_key kritikus fontosságú: ha ugyanaz az order_id ismét megjelenik a forrásban (pl. frissített státusz), a dbt az insert helyett update műveletet hajt végre. Ez biztosítja az idempotenciát — bármennyiszer is futtatjuk a modellt, az eredmény mindig konzisztens. A merge stratégia (ami a háttérben történik) a forrásadatokat a cél táblával összehasonlítja, és csak a különbségeket alkalmazza.

Tip: Mindig adj meg unique_key-t incremental modellekhez! Enélkül a dbt nem tudja, mely sorokat kell frissíteni, és duplikációk keletkezhetnek. Ha nincs természetes egyedi kulcsod, generálj egyet surrogate key-ből (lásd a Macros szekciót).

[9]
-- models/marts/fct_orders_incremental.sql
{{ config(materialized='incremental', unique_key='order_id') }}

with orders as (
    select * from {{ ref('stg_orders') }}
)
select * from orders
{% if is_incremental() %}
where ordered_at > (select max(ordered_at) from {{ this }})
{% endif %}
Output:
$ dbt run --select fct_orders_incremental
Incremental: inserted 45 new rows (total: 1420)
Section 10

Snapshots: SCD Type 2

A snapshot-ok a dbt SCD Type 2 (Slowly Changing Dimension) implementációi: automatikusan nyomon követik, hogyan változnak az adatok az idő múlásával. Amikor egy rendelés státusza „pending"-ről „shipped"-re változik, a snapshot nem csak felülírja az értéket, hanem megtartja a régit is, egy érvényességi időablakkal (valid_from, valid_to) ellátva. Ez lehetővé teszi, hogy bármely időpontra visszaállítsuk az adatok állapotát — „milyen volt a rendelés státusza múlt kedden?"

A példában a timestamp stratégia alapján működik a snapshot: az updated_at oszlop változását figyeli. Ha egy sor updated_at értéke megváltozik, a dbt a régi sort lezárja (valid_to beállítása) és egy új sort beszúr az új értékekkel. A target_schema='snapshots' külön sémába helyezi a históriai táblákat, elkülönítve őket az aktuális adatoktól. A unique_key biztosítja, hogy a megfelelő sor frissüljön.

A snapshot-ok különböznek az incremental modellektől: míg az incremental csak az új adatokat adja hozzá, a snapshot a meglévő sorok változásait is követi. Ezért a snapshotokat tipikusan dimenzió táblákon (ügyfelek, termékek, rendelések) használjuk, ahol a változások történetének megőrzése üzleti igény. Fact táblákon (tranzakciók, események) ritkábban van szükség rá.

Tip: Futtasd a snapshot-okat rendszeresen (pl. naponta), és ne felejtsd el, hogy a snapshot futtatás az addigi adatbázis-állapottól függ — ha kihagyol egy futtatást, a változások nem kerülnek rögzítésre. Automatizáld a dbt snapshot parancsot a CI/CD pipeline-ban vagy egy scheduler-ben.

[10]
# snapshots/orders_snapshot.sql
{% snapshot orders_snapshot %}

{{ config(
    target_schema='snapshots',
    unique_key='order_id',
    strategy='timestamp',
    updated_at='updated_at',
) }}

select * from {{ ref('stg_orders') }}

{% endsnapshot %}
Output:
$ dbt snapshot
OK snapshot snapshots.orders_snapshot [INSERT 45, UPDATE 12]
Section 11

Macros: újrahasználható kód

A macro-k a dbt Jinja templating rendszerének legfontosabb elemei: újrahasználható SQL kódblokkok, amelyeket több modellben is meghívhatsz. A macro-k hasonlóak a függvényekhez a programozásban — definiálsz egy logikát egyszer, és aztán bárhonnan hivatkozhatsz rá. Ez kiküszöböli a kódduplikációt és biztosítja, hogy ha egy logikát módosítani kell, azt csak egy helyen kell megtenni.

A példa két gyakori macro-t mutat be. A cast_timestamp egy egyszerű típuskonverziós segédfüggvény, amely egy oszlopnevet vesz át és timestamp-é konvertálja. A generate_surrogate_key egy összetettebb macro: egy oszlopnév-listát vesz át, azokat egy separator-sal összekapcsolja, majd MD5 hash-t számít belőle. Ez egy gyakori minta a data warehouse-ban, ahol a természetes kulcsokból (pl. customer_id + product_id) mesterséges egyedi kulcsot generálunk.

A macro-k használatával a modellben csak ennyit kell írni: select generate_surrogate_key(['customer_id', 'product_id']) as order_sk — a dbt a futtatás előtt kifejti a Jinja sablont valódi SQL-lé. A macro-k paramétereket is fogadhatnak, tartalmazhatnak feltételes logikát (if/else), ciklusokat (for), és hivatkozhatnak más macro-kra is. Ez rendkívül rugalmas kód-újrahasznosítást tesz lehetővé.

Tip: Hozz létre egy macros/ mappán belül egy utils/ alkönyvtárat az általános segédfüggvényeknek (surrogate key, date formatting), és külön fájlokat az üzleti specifikus macro-knak. Ne használj macro-t olyan egyszerű logikára, amit egy sor SQL is megold — a macro-k a valóban ismétlődő mintákhoz valók.

[11]
-- macros/cast_timestamp.sql
{% macro cast_timestamp(column_name) %}
    {{ column_name }}::timestamp
{% endmacro %}

-- macros/generate_surrogate_key.sql
{% macro generate_surrogate_key(columns) %}
    md5(concat({{ columns | join("||'|'||") }}))
{% endmacro %}

-- Usage in model:
select {{ generate_surrogate_key(['customer_id', 'product_id']) }} as order_sk
Output:
Macro defined: cast_timestamp, generate_surrogate_key
Used in 5 models
Section 12

Dokumentáció

A dokumentáció a dbt egyik legerősebb beépített funkciója. A models YML fájlokban leírt description mezőkből, oszlopleírásokból és a modell-kódból a dbt automatikusan generál egy interaktív weboldalt, amely tartalmazza a modellek leírását, a DAG lineage diagramot, az oszlopok dokumentációját és a teszteredményeket is. A dbt docs generate parancs létrehozza a dokumentációs fájlokat, a dbt docs serve pedig egy lokális weboldalon teszi elérhetővé.

A példában a fct_monthly_revenue modellhez írunk leírást: a month oszlop dokumentálja, hogy a hónap első napjára van csonkolva (date_trunc), a revenue pedig megjegyzi, hogy a visszamondott rendeléseket kizárja. Ezek a leírások a generált dokumentációban mindenki számára láthatóvá válnak — a data engineer-ek, az analitikusok és az üzleti felhasználók számára egyaránt.

A dokumentáció nem „utólagos kötelező" — hanem a fejlesztési folyamat szerves része. Amikor egy új modellt hozol létre, azonnal írd le, mit csinál és miért. Ha egy kolléga hetek múlva meg akarja érteni a modellt, a dokumentáció (és a kód) elég kell legyen — nem kellene elolvasnia egy régi Slack beszélgetést. A jó dokumentáció csökkenti a tudás-szigeteket és javítja a csapat termelékenységét.

Tip: Használd a dbt docs-ot a „knowledge base" építéséhez. A lineage diagram gyakran a leghasznosabb rész — az üzleti felhasználók vizuálisan látják, honnan származnak az adataik, és melyik modellre támaszkodhatnak. Ha a dokumentációt CI/CD-ben automatikusan generálod, mindig naprakész marad.

[12]
# models/marts/_marts__yml.yml
models:
  - name: fct_monthly_revenue
    description: 'Monthly revenue by category and segment'
    columns:
      - name: month
        description: 'Truncated to first day of month'
      - name: revenue
        description: 'Sum of order amounts, excluding cancelled'

# Generate docs
dbt docs generate
dbt docs serve
Output:
$ dbt docs generate
Built documentation with 12 models, 34 columns
$ dbt docs serve
Serving at http://localhost:8080
Section 13

Tags és meta

A tags és meta mezők a dbt modellek szervezésének és kezelésének eszközei. A tags egyszerű címkék, amelyekkel csoportosíthatod a modelleket — például 'mart', 'revenue', 'daily'. A meta mező strukturált metaadatokat tárol: tulajdonost (owner), SLA-t, frissítési gyakoriságot (refresh_frequency), vagy bármilyen egyedi kulcs-érték párt. Ezek az információk a dbt docs-ban megjelennek, és a parancssorból is lekérdezhetők.

A példában a fct_monthly_revenue modell owner-je az 'analytics-team', az SLA 4 óra (ennyi időn belül frissülnie kell), és napi frissítésű. A tags segítségével a dbt run --select tag:mart paranccsal lefuttathatod az összes mart modellt anélkül, hogy mindegyiket név szerint listáznád. Hasonlóan, a meta alapján is szűrhetsz: dbt run --select 'config.meta.owner:analytics-team' lefutja az összes modellt, amely az analytics team-hez tartozik.

Ezek a funkciók nagyobb projektekben válnak igazán hasznossá. Ha 50+ modell van a projektedben, nem praktikus minden futtatáskor az összeset újraépíteni. A tags és meta segítségével szelektíven futtathatod csak a szükséges modelleket — például csak a napi frissítésűeket, vagy csak egy adott csapat modelljeit. Ez jelentős idő- és költségmegtakarítást eredményez, különösen felhő adatbázisoknál.

Tip: Definiálj egy konvenciót a tags és meta használatára a csapatban. Kötelező mezők: owner (ki felel a modellért), SLA (milyen gyakran kell frissülnie), és refresh_frequency (napi, óránkénti, stb.). Ezek az információk nemcsak a futtatást segítik, hanem az üzemeltetési dokumentációt is gazdagítják.

[13]
models:
  - name: fct_monthly_revenue
    meta:
      owner: 'analytics-team'
      sla: '4 hours'
      refresh_frequency: 'daily'
    tags: ['mart', 'revenue']

# Run by tag
dbt run --select tag:mart

# Run by meta
dbt run --select 'config.meta.owner:analytics-team'
Output:
$ dbt run --select tag:mart
Running 3 models with tag 'mart'
Section 14

Teljes WebShop Pro analytics layer

Ez a szekció a teljes WebShop Pro analytics layer rendszerét foglalja össze. A projekt 8 modellt tartalmaz három rétegben: 3 staging modell (stg_orders, stg_products, stg_customers), amelyek a nyers adatokat tisztítják; 2 intermediate modell (int_orders_enriched, int_customer_segments), amelyek join-okkal dúsítják az adatokat; és 3 mart modell (fct_monthly_revenue, dim_customers, dim_products), amelyek az üzleti felhasználásra kész aggregációkat és dimenziókat szolgáltatják. Az egész rendszert 15 teszt védi (schema és custom tesztek együtt).

A dbt run parancs lefuttatja az összes modellt a megfelelő sorrendben — a DAG alapján a dbt automatikusan tudja, hogy a staging modelleket előbb kell lefuttatni, mint az intermediate-eket, és azokat előbb, mint a mart-okat. A dbt test ellenőrzi mind a 15 tesztet, a dbt docs generate pedig létrehozza a teljes dokumentációt, benne a lineage diagrammal. Ez a három parancs együttesen adja a dbt workflow gerincét.

Ez a projekt jó kiindulópont a valódi analytics projektekhez. A valóságban ehhez jönnek még: forrás-freshness monitoring, snapshot-ok a változáskövetésre, macro-k a kód-újrahasznosításra, és CI/CD automatizáció. A lépték is nagyobb lehet — egy valós e-kereskedelmi vállalatnál 50-200 modell is előfordulhat. De az alapelvek ugyanazok: réteges architektúra, tesztelés, dokumentáció, és automatizáció.

Tip: Használd ezt a projektet sablonként a saját munkádhóz. A struktúra (staging/intermediate/mart), a konvenciók (stg_, int_, fct_, dim_ prefixek), és a tesztelési megközelítés közvetlenül átemelhetők más projektekbe. Csak cseréld ki a forrásokat és az üzleti logikát a saját igényeidre.

[14]
# Run the full project
dbt run

# Run all tests
dbt test

# Generate docs
dbt docs generate

# Summary
echo 'Models: 8 (3 staging, 2 intermediate, 3 mart)'
echo 'Tests: 15 (schema + custom)'
echo 'Sources: 3 tables with freshness checks'
Output:
$ dbt run
OK: stg_orders, stg_products, stg_customers
OK: int_orders_enriched, int_customer_segments
OK: fct_monthly_revenue, dim_customers, dim_products

$ dbt test
15 of 15 tests passed

Docs available at http://localhost:8080
Section 15

Összefoglalás

Gratulálunk! Sikeresen felépítetted a WebShop Pro analytics layer-t — egy teljes, réteges adattranszformációs rendszert, amely a nyers adatoktól az üzleti döntéstámogatásig vezet. A kurzus során megismerted a dbt minden főbb funkcióját: a staging/intermediate/mart architektúrát, a schema és custom teszteket, az incremental modelleket, a snapshot-okat, a macro-kat, és a dokumentáció generálását.

A megtanult technikák közvetlenül alkalmazhatók a valódi munkában. A réteges modellstruktúra (Bronze/Silver/Gold) iparági standard, amelyet a legnagyobb technológiai vállalatok is használnak. A teszt-vezérelt adatfejlesztés (test-driven data development) biztosítja, hogy az adatok minősége ne romoljon a rendszer növekedésével. A dokumentáció és lineage pedig a csapatmunkát és a tudásmegosztást segíti.

A következő lépés a Databricks Lakehouse kurzus, ahol a dbt-ben tanult elveket egy managed felhői környezetben fogod alkalmazni. A Delta Live Tables, a Unity Catalog és az MLflow integrációkkal egy production-ready data platform-ot fogsz építeni. A dbt és a Databricks kiegészítik egymást — sok vállalat használja a kettőt együtt.

Tip: Gyakorolj! Hozz létre egy saját dbt projektet a saját adataiddal (akár egy nyilvános dataset-tel). Minél többet használod a dbt-t, annál természetesebbé válik a modellstruktúra, a tesztelés és a dokumentáció írása. A tapasztalat a legjobb tanár.

MegtanultukKövetkező
Staging/Intermediate/MartDatabricks Lakehouse
Schema tesztek, incrementalProduction deployment
Snapshots, macrosDelta Live Tables
Dokumentáció, lineageUnity Catalog
Következő

Databricks Lakehouse - ahol managed környezetben dolgozunk!

Quiz: Mi a staging réteg célja?

Quiz: Melyik dbt materialization épít újra minden futáskor?