---
title: 'Dönüştürme Çerçeveleri'
source: 'https://academia.sh/tr/kurslar/veri-hatlari/donusturme-cerceveleri'
course: 'Veri Hatları ve Orkestrasyon'
language: tr
updated: '2026-08-17T18:08:50+00:00'
license: 'CC BY-SA 4.0'
---

# Dönüştürme Çerçeveleri

Dönüşümlerin birbirine başvuran modeller olarak yazılmasının ve sıranın nereden geldiğinin sayılması: on bir model ve on üç bildirilen bağımlılık üzerinde çözümleyici sırası 0 ihlal verirken elle tutulan yazılma sırası 1 bağımlılığı ihlal edip 7 modeli, alfabetik sıra 5 bağımlılığı ihlal edip 10 modeli eksik girdiyle koşturuyor; ihlalli koşum hiçbir hata üretmeden sunumu her bölgede 17,46 ile 28,37 arasında düşürüyor; sorgu metnine bir başvuru daha eklendiğinde çözümleyici 11 modelin yalnız 3'ünü sıralayıp koşumu başlatmıyor, elle sıra ise on birini de koşturup döngünün bir kenarını sessizce kırıyor; bildirilmemiş tek bir okuma çizgede hiç görünmediği için çözümleyici 0 ihlal bildirirken gerçek ihlal 1 oluyor.

Önceki ders dönüşümün nerede koşacağını sordu ve üç kurulumu yan yana koydu. Üçü de tek bir
varsayımı paylaşıyordu: dönüşüm beş aşamalı, sırası sabit ve tek bir kişinin aklında tutabileceği
bir zincirdir. Bir hedefte biriken dönüşüm katmanı ise tek bir zincir değildir; birbirine referans
veren onlarca ayrı çıktıdır ve bunların bir kısmı hiç sunuma bağlanmaz.

Bu ders o çıktıları **model** olarak yazar. Bir model adı olan tek bir çıktıdır ve tanımı bir
sorgudur. Ölçülen iki şey vardır: bağımlılık çözümünün sıraladığı görev ve **elle tutulan sıranın
kaçırdığı bağımlılık**. İkincisinin bedeli bu derste hata olarak değil, hatasız üretilmiş yanlış bir
sayı olarak görünür.

- **DN9.** Model kaydı, sorgu metinleri ve çözümleyici **kurgudur**; hiçbir dönüştürme çerçevesi,
  sorgu motoru ya da veri ambarı ürünü çağrılmaz. Tohum **20260218**.
- **DN10.** Bir modelin bağımlılığı sorgu metnindeki `ref(...)` çağrılarından **çıkarılır**; ayrı
  bir listede tutulmaz. Referansı yazmak ile bağımlılığı bildirmek tek bir iştir.
- **DN11.** Modeller bir **yönlü çevrimsiz çizgenin (directed acyclic graph)** düğümleridir.
  Topolojik sıralama algoritması Bilgisayar Bilimi müfredatının Veri Yapıları kursunda, Çizgeler
  konusunda ölçüldü ve **tekrarlanmaz**; burada çizge kurulur ve kullanılır.
- **DN12.** Ölçülen koşum **ilk koşumdur**: hiçbir tablo daha önce yazılmamıştır. Sırası gelmeden
  okunan bir model **boş tablo** okur ve hata vermez.
- **DN13.** Taban çizgisi **elle tutulan sıradır**: bağımlılık çözümü yok, ihlal sayacı yok, döngü
  denetimi yok.
- **DN14.** Üretici son dönemin işyeri okumalarını yeniden okumuş ve endeksleri 12 fazla bulmuştur.
  Bu bir bozulma değil, sıradan bir **üretici düzeltmesidir**.
- **DN15.** Sayılan birimler görev, ihlal edilen bağımlılık ve **bozulan model**dir. Bozulan model,
  eksik girdiyle koşan modelin kendisi ve ondan erişilen bütün modellerdir.
- **DN16.** Çözünürlük: model **11**, bildirilen bağımlılık **13**, sunum **5 değer**. **Sunum
  üzerinde oran basılmaz**, değerin kendisi yazılır.

## Modelin Bağımlılığı Kendi Metnindedir

Elle tutulan bir sıra listesi ile çözümlenmiş bir çizge arasındaki fark, bağımlılığın **nerede
yazıldığıdır**. Listede sıra ayrı bir belgedir: sorgu bir yerde, sıra başka bir yerde durur ve
ikisini tutarlı tutmak insanın işidir. Referans tabanlı yazımda ise bağımlılık sorgunun **içindedir**:
bir modelin başka bir modeli okuması, o modeli `ref(...)` ile adlandırmasıyla aynı şeydir. Çizge bu
adlardan çıkarılır, dolayısıyla sorgu değiştiği anda çizge de değişir.

İlk blok önceki derslerin kurgu hattını kurar ve üzerine sıralamayı ekler.

```python
# KURGUDUR. Sayac okumalari, bes asamali hat ve model kaydi ders icinde tanimlanir;
# gercek bir donusturme cercevesi, sorgu motoru ya da veri ambari cagrilmaz.
import re

TOHUM, M32 = 20260218, 0xFFFFFFFF


def uretec(t):
    x = ((t ^ (t >> 16)) * 2246822507) & M32
    x = ((x ^ (x >> 13)) * 3266489909) & M32
    s = [(x ^ (x >> 16)) & M32]

    def sonraki():
        s[0] = (s[0] * 1664525 + 1013904223) & M32
        return s[0] / 4294967296
    return sonraki


BOLGE = ["dogu", "bati", "kuzey", "guney", "merkez"]
TIP = ["mesken", "isyeri"]
DONEM = [f"2026-{a:02d}" for a in range(1, 13)]
ABONE = {}
for i in range(200):
    r = uretec(TOHUM + 37 * i)
    ABONE[f"A{i + 1:03d}"] = {"bolge": BOLGE[int(r() * 5)], "tip": TIP[int(r() * 2)],
                              "baslangic": 10000 + int(r() * 60000)}


def kaynak_uret():
    kayit = []
    for i, (ab, a) in enumerate(ABONE.items()):
        e = a["baslangic"]
        for d in DONEM:
            r = uretec(TOHUM + 101 * i + 7 * DONEM.index(d))
            e += 4 + int(r() * 46)
            kayit.append({"abone": ab, "donem": d, "bolge": a["bolge"], "tip": a["tip"],
                          "endeks": e, "birim": "m3"})
    return kayit


def a1_ayikla(kayit):
    ZOR = ("abone", "donem", "bolge", "endeks", "birim")
    tut = [k for k in kayit if all(a in k for a in ZOR)]
    return tut, len(kayit) - len(tut)


def a2_tekille(kayit):
    gor, tut = set(), []
    for k in kayit:
        ad = (k["abone"], k["donem"])
        if ad in gor:
            continue
        gor.add(ad)
        tut.append(k)
    return tut, len(kayit) - len(tut)


def a3_tuketim(kayit):
    tablo = {(k["abone"], k["donem"]): k for k in kayit}
    cikti, dusen = [], 0
    for k in kayit:
        i = DONEM.index(k["donem"])
        if i == 0:
            continue
        onceki = tablo.get((k["abone"], DONEM[i - 1]))
        if onceki is None:
            dusen += 1
            continue
        try:
            f = int(k["endeks"]) - int(onceki["endeks"])
        except (TypeError, ValueError):
            dusen += 1
            continue
        cikti.append(dict(k, m3=f))
    return cikti, dusen


def a4_ozet(kayit):
    top = {}
    for k in kayit:
        ad = (k["bolge"], k["donem"])
        top[ad] = top.get(ad, 0) + k["m3"]
    return top, 0


def a5_sun(ozet):
    bolge = {}
    for (b, d), v in ozet.items():
        bolge.setdefault(b, []).append(v)
    return {b: round(sum(v) / len(v), 2) for b, v in bolge.items()}, 0


def sirala(dugum, kenar):
    """Yonlu cevrimsiz cizgede calistirma sirasi."""
    gelen = {u: 0 for u in dugum}
    ardil = {u: [] for u in dugum}
    for a, b in kenar:
        gelen[b] += 1
        ardil[a].append(b)
    hazir = [u for u in dugum if gelen[u] == 0]
    sira = []
    while hazir:
        u = hazir.pop(0)
        sira.append(u)
        for v in ardil[u]:
            gelen[v] -= 1
            if gelen[v] == 0:
                hazir.append(v)
    return sira, ardil
```

On bir model bir sözlükte durur. `duzeltme` en son eklenendir: üretici son dönemin işyeri
okumalarını yeniden okumuş, düzeltilmiş endeksleri ayrı bir çıktı olarak yayımlamıştır ve `tuketim`
artık onu da okur.

```python
SORGU = {
    "ham_okuma":    "select * from kaynak",
    "ayiklanmis":   "select * from ref('ham_okuma') where zorunlu alanlar dolu",
    "tekil":        "select * from ref('ayiklanmis') group by abone , donem",
    "duzeltme":     "select abone , donem , yeni_endeks from ref('ayiklanmis')",
    "tuketim":      "select * from ref('tekil') left join ref('duzeltme')",
    "bolge_donem":  "select bolge , donem , sum(m3) from ref('tuketim')",
    "bolge_sunum":  "select bolge , avg(toplam) from ref('bolge_donem')",
    "tip_donem":    "select tip , donem , sum(m3) from ref('tuketim')",
    "bolge_tip":    "select * from ref('bolge_donem') join ref('tip_donem')",
    "abone_yillik": "select abone , sum(m3) from ref('tuketim')",
    "tazelik":      "select count(*) from ref('ham_okuma') , ref('bolge_sunum')",
}
REF = re.compile(r"ref\('(\w+)'\)")


def cizge_kur(sorgu):
    """Kenarlar sorgu metnindeki referanslardan cikarilir , ayri bir listeden degil."""
    dugum = list(sorgu)
    kenar = [(o, m) for m, s in sorgu.items() for o in dict.fromkeys(REF.findall(s))]
    return dugum, kenar


def ihlal(sira, kenar):
    """Verilen sirada once kosmasi gereken hangi model sonra kosuyor."""
    yer = {u: i for i, u in enumerate(sira)}
    return [(a, b) for a, b in kenar if yer[a] > yer[b]]


def bozulan(kenar, ihlaller):
    """Eksik girdiyle kosan model: ihlalin hedefi ve ondan erisilen her sey."""
    ardil = {}
    for a, b in kenar:
        ardil.setdefault(a, []).append(b)
    yigin = [b for _, b in ihlaller]
    kapali = set(yigin)
    while yigin:
        u = yigin.pop()
        for v in ardil.get(u, []):
            if v not in kapali:
                kapali.add(v)
                yigin.append(v)
    return kapali


DUGUM, KENAR = cizge_kur(SORGU)
SIRA, _ = sirala(DUGUM, KENAR)
YAZILMA = ["ham_okuma", "ayiklanmis", "tekil", "tuketim", "bolge_donem", "bolge_sunum",
           "tazelik", "abone_yillik", "tip_donem", "bolge_tip", "duzeltme"]
SIRALAR = [("cozumleyici", SIRA), ("elle , yazilma sirasi", YAZILMA),
           ("elle , alfabetik", sorted(DUGUM))]

print("model:", len(DUGUM), " bildirilen bagimlilik:", len(KENAR))
print("cozumleyicinin sirasi:", SIRA)
print()
print(f"{'sira':<24}{'model':>7}{'ihlal':>7}{'bozulan':>9}  ihlali doguran model")
for ad, s in SIRALAR:
    iv = ihlal(s, KENAR)
    print(f"{ad:<24}{len(s):>7}{len(iv):>7}{len(bozulan(KENAR, iv)):>9}  {[a for a, _ in iv]}")
```

```
model: 11  bildirilen bagimlilik: 13
cozumleyicinin sirasi: ['ham_okuma', 'ayiklanmis', 'tekil', 'duzeltme', 'tuketim', 'bolge_donem', 'tip_donem', 'abone_yillik', 'bolge_sunum', 'bolge_tip', 'tazelik']

sira                      model  ihlal  bozulan  ihlali doguran model
cozumleyici                  11      0        0  []
elle , yazilma sirasi        11      1        7  ['duzeltme']
elle , alfabetik             11      5       10  ['ham_okuma', 'tuketim', 'tuketim', 'tip_donem', 'tuketim']
```

Çözümleyici on bir modeli sıralıyor ve on üç bağımlılığın hiçbirini ihlal etmiyor. İlgi çekici olan
öbür iki satırdır. Yazılma sırası, modellerin depoya eklendiği tarih sırasıdır ve `duzeltme`
eklenene kadar **kusursuzdu**: on modelin sırası doğruydu. Yeni model listenin sonuna yazıldı,
çünkü yeni şeyler oraya yazılır. Onu okuyan `tuketim` ise listenin dördüncü sırasındadır. **Tek bir
ihlal** budur, ve o tek ihlal on bir modelin **yedisini** eksik girdiyle koşturur.

Alfabetik sıra daha kötüdür ve daha dürüsttür: beş bağımlılığı ihlal eder, on modeli bozar. Kaynak
okumasının kendisi ikinci sıraya düşen `ayiklanmis`tan sonra koştuğu için zincirin tamamı boşta
kalır. İki satır arasındaki fark ihlal sayısı değil, ihlalin **görünürlüğüdür**.

## Sıra Bozulduğunda Ne Oluyor

İhlal sayısı bir sayaçtır; asıl soru koşumun ne ürettiğidir. Üçüncü blok her sırayı gerçekten
koşturur. Sırası gelmemiş bir modelin tablosu henüz yazılmamıştır, dolayısıyla onu okuyan model
**boş tablo** okur ve hata vermez.

```python
def topla(kayit, alan, ikili=True):
    t = {}
    for k in kayit:
        ad = (k[alan], k["donem"]) if ikili else k[alan]
        t[ad] = t.get(ad, 0) + k["m3"]
    return t


def pay(bolge_donem, tip_donem):
    """Bolgenin donem toplamindaki payi."""
    donem = {}
    for (t, dn), v in tip_donem.items():
        donem[dn] = donem.get(dn, 0) + v
    return {(b, dn): round(v / donem[dn], 4) for (b, dn), v in bolge_donem.items()
            if donem.get(dn)}


# Uretici son donemin isyeri okumalarini yeniden okudu: endeks 12 fazla cikti.
ISLEV = {
    "ham_okuma": lambda d: kaynak_uret(),
    "ayiklanmis": lambda d: a1_ayikla(d["ham_okuma"])[0],
    "tekil": lambda d: a2_tekille(d["ayiklanmis"])[0],
    "duzeltme": lambda d: {(k["abone"], k["donem"]): k["endeks"] + 12
                           for k in d["ayiklanmis"]
                           if k["donem"] == "2026-12" and k["tip"] == "isyeri"},
    "tuketim": lambda d: a3_tuketim([dict(k, endeks=d["duzeltme"].get(
        (k["abone"], k["donem"]), k["endeks"])) for k in d["tekil"]])[0],
    "bolge_donem": lambda d: a4_ozet(d["tuketim"])[0],
    "bolge_sunum": lambda d: a5_sun(d["bolge_donem"])[0],
    "tip_donem": lambda d: topla(d["tuketim"], "tip"),
    "abone_yillik": lambda d: topla(d["tuketim"], "abone", ikili=False),
    "bolge_tip": lambda d: pay(d["bolge_donem"], d["tip_donem"]),
    "tazelik": lambda d: {"ham": len(d["ham_okuma"]), "bolge": len(d["bolge_sunum"])},
}
LISTE = ("ham_okuma", "ayiklanmis", "tekil", "tuketim")
BOS = {ad: ([] if ad in LISTE else {}) for ad in SORGU}


def kostur(sira):
    """Ilk kosum: sirasi gelmeden okunan model bos tablo okur."""
    depo = dict(BOS)
    for ad in sira:
        depo[ad] = ISLEV[ad](depo)
    return depo


for ad, s in SIRALAR:
    print(f"{ad:<24}{kostur(s)['bolge_sunum']}")
```

```
cozumleyici             {'merkez': 1349.82, 'kuzey': 1232.18, 'dogu': 898.82, 'bati': 853.82, 'guney': 1090.64}
elle , yazilma sirasi   {'merkez': 1321.45, 'kuzey': 1212.55, 'dogu': 881.36, 'bati': 833.09, 'guney': 1065.55}
elle , alfabetik        {}
```

Üçüncü satır beklenen başarısızlıktır: alfabetik sıra hiç sunum üretmiyor. Boş bir sözlük hiç kimseyi
yanıltmaz; ilk bakan kişi bir şeyin yanlış gittiğini görür.

İkinci satır dersin asıl bulgusudur. Yazılma sırası **beş bölge için de eksiksiz bir sunum**
üretiyor. Değerler makul aralıkta, bölgeler arası ilişki doğru, hiçbir alan boş değil ve koşum
hatasız tamamlanmış. Tek sorun sayıların yanlış olmasıdır: `duzeltme` tablosu `tuketim`den sonra
yazıldığı için düzeltilmiş endeksler hesaba hiç girmiyor. Doğru sunumla arasındaki fark her bölgede
17,46 ile 28,37 arasında. Bu, kursun üçüncü iddiasının bu dersteki hâlidir: **çıktıya bakmak
yetmez.** Yanlış sıra çökmedi, uyarmadı, boş bırakmadı; yalnızca sessizce eski veriyi kullandı.

Farkın kaynağı tek bir modeldir, ama etkisi tek bir modelle sınırlı değildir. Bozulan model sayısı
yedidir: `tuketim` eksik girdiyle koştuğu için ondan beslenen bölge özeti, bölge sunumu, tip özeti,
bölge–tip payı, abone yıllığı ve tazelik raporu da eski sayıyı taşır. Bir bağımlılığı kaçırmanın
bedeli, kaçırılan bağımlılığın **aşağısında kalan her şeydir**.

## Çözümleyicinin Göremediği İki Şey

Çözümleyici bağımlılığı sorgudan çıkarır, dolayısıyla sorgunun söylediğinden fazlasını bilemez. İki
durum bunun sınırını gösterir: sorgunun **fazla** söylediği durum ve **eksik** söylediği durum.

```python
DONGULU = dict(SORGU, duzeltme=SORGU["duzeltme"] + " where bolge in ref('bolge_sunum')")
D2, K2 = cizge_kur(DONGULU)
S2, _ = sirala(D2, K2)
print("dongulu kayit  model:", len(D2), " bagimlilik:", len(K2))
print("cozumleyici    siralanan:", len(S2), " siralanamayan:", len(D2) - len(S2),
      " siralananlar:", S2)
print("elle sira      kosan model:", len(YAZILMA),
      " kirilan kenar:", len(ihlal(YAZILMA, K2)))
print()

GERCEK = KENAR + [("bolge_sunum", "abone_yillik")]
print("bildirilen bagimlilik:", len(KENAR), " gercek bagimlilik:", len(GERCEK))
print("cozumleyicinin bildirdigi ihlal:", len(ihlal(SIRA, KENAR)),
      " gercek ihlal:", len(ihlal(SIRA, GERCEK)),
      " bozulan model:", len(bozulan(GERCEK, ihlal(SIRA, GERCEK))))
```

```
dongulu kayit  model: 11  bagimlilik: 14
cozumleyici    siralanan: 3  siralanamayan: 8  siralananlar: ['ham_okuma', 'ayiklanmis', 'tekil']
elle sira      kosan model: 11  kirilan kenar: 1

bildirilen bagimlilik: 13  gercek bagimlilik: 14
cozumleyicinin bildirdigi ihlal: 0  gercek ihlal: 1  bozulan model: 1
```

Birinci durumda `duzeltme` modeline yayımlanmış bölge sunumuna bakan bir koşul eklenmiştir. Bu
sıradan bir istektir ve tek bir referanstır, ama çizgeye bir çevrim sokar: bölge sunumu tüketimden,
tüketim düzeltmeden, düzeltme de bölge sunumundan gelmektedir. Çözümleyici on bir modelin yalnızca
**üçünü** sıralayabiliyor, **sekizi** sıralanamıyor ve koşum hiç başlamıyor. Elle tutulan sıra ise
on bir modeli de koşturuyor ve döngünün bir kenarını **kırılan kenar sayısı 1** olarak, hiçbir yere
yazmadan geçiyor. **Doğrusal bir liste bir döngüyü döngü olarak gösteremez**; yalnızca döngünün bir
kenarını seçip sessizce kırar. Çözümleyicinin koşmayı reddetmesi bir arıza değil, döngünün tek
görünür kanıtıdır.

İkinci durum çözümleyicinin kendi bedelidir. Bir model, başka bir modelin çıktısını `ref(...)`
yerine tablonun fiziksel adıyla okursa bu okuma sorgu metninde başvuru olarak **görünmez**. Gerçek
bağımlılık on dörttür, bildirilen on üç. Çözümleyici kendi çizgesini kusursuz sıralar ve **0 ihlal**
bildirir; gerçek ihlal **1**, bozulan model **1**'dir. Çözümleyicinin ürettiği güvence çizgenin
doğruluğuna değil, **bildirimin eksiksizliğine** dayanır. Bildirilmeyen her okuma, yeşil bir raporun
altında saklanır.

## Özet

- Bir modelin bağımlılığı ayrı bir sıra listesinde değil, kendi sorgu metnindeki `ref(...)`
  çağrılarında durur; çizge o metinden çıkarıldığı için sorgu değiştiğinde çizge de değişir.
- On bir model ve on üç bağımlılıkta çözümleyici **0 ihlal** verir; yazılma sırası **1**, alfabetik
  sıra **5** bağımlılığı ihlal eder ve sırasıyla **7** ile **10** modeli eksik girdiyle koşturur.
- Sonradan eklenen tek bir model elle tutulan sırayı bozmaya yeter, çünkü yeni model listenin sonuna
  yazılır ama çizgede yukarıda durur.
- İhlalli koşum hata vermez: beş bölge için eksiksiz bir sunum üretir ve doğru sunumdan her bölgede
  17,46 ile 28,37 arasında sapar. Boş çıkan alfabetik koşum, yanlış sayı üreten koşumdan daha az
  tehlikelidir.
- Sorguya tek bir başvuru eklemek çizgeye çevrim sokabilir: çözümleyici 11 modelin 3'ünü sıralayıp
  koşumu başlatmaz, elle sıra on birini de koşturup döngünün bir kenarını sessizce kırar.
- Çözümleyicinin güvencesi bildirimin eksiksizliğine dayanır: bildirilmemiş tek bir okuma gerçek
  bağımlılığı 14'e çıkarır, çözümleyici yine **0 ihlal** bildirir ve gerçek ihlal 1 olur.

## Sonraki Adım

Bu dersin on bir modeli tek bir düzlemde duruyordu: hepsi eşit ölçüde kalıcı, hepsi eşit ölçüde
sorgulanabilir. Gerçek bir dönüştürme katmanında bu modeller **katmanlara** ayrılır ve katmanların
her biri farklı bir söz verir. Ham katman kaynağı olduğu gibi saklar, arıtılmış katman kuralları
uygular, sunum katmanı yalnızca yayımlanacak olanı taşır. Bu ayrımın bedeli aynı verinin birden çok
kez saklanmasıdır; karşılığı ise bir bozulmanın **aşağıya inmeden durdurulabilmesidir**. Sonraki ders
her katmanın sakladığı satırı sayar ve önceki kursun altı bozulma sınıfını bu üç katmana dağıtarak
her birinin hangi katmanda durdurulabildiğini ölçer.
