---
title: 'Ters ETL'
source: 'https://academia.sh/tr/kurslar/veri-hatlari/ters-etl'
course: 'Veri Hatları ve Orkestrasyon'
language: tr
updated: '2026-08-17T18:08:49+00:00'
license: 'CC BY-SA 4.0'
---

# Ters ETL

İşlenmiş verinin operasyonel sisteme geri yazılmasının açtığı çemberin sayılması: sunum katmanında hesaplanan bölge eşiği geri yazıldığında zincir al, ayikla, tekille, tuketim, ozet, sun ve geri yazım üzerinden yedi aşama sonra kendi girdisine dönüyor. Geri yazılan değerin bir sonraki koşumda yaptığı ölçülüyor: birinci koşumun yazdığı eşik ikinci koşumda 1129 okumayı kırpıyor, sunum her koşumda kayıyor (koşumlar arası en büyük fark 47,00, sonra 10,90 ve 14,36) ve döngü dördüncü koşumda duruyor. Durduğu yer taban değildir: tüketim satırı 2200'de kalırken 55 özet hücresinin 55'i kirleniyor, sunum −19,27 … −59,46 sapıyor ve en büyük hücre sapması 0,1788 ile 0,25 eşiğinin altında kaldığı için hiçbir denetim ateşlemiyor. Geri yazılan değer hattın girdisinden ayrı tutulduğunda her koşum aynı sonucu veriyor.

Önceki beş derste veri hep tek yönde aktı: kaynak sistemden hatta, hattan özete, özetten sunuma. Bu
yön bütün ölçülerin sessiz varsayımıydı. Oysa sunum katmanındaki bir sayı çoğu kez orada kalmaz.
Bölge başına beklenen tüketim, bir abonenin risk sınıfı ya da bir bölgenin eşiği, asıl işini bir
gösterge tablosunda değil **sahada** yapar: okuma yapan uygulama onu kullanır, faturalama onu
uygular, uyarı düzeneği ona bakar. İşlenmiş verinin operasyonel sisteme geri yazılmasına **ters
ETL** denir ve bu bir hattın en meşru çıktılarından biridir.

Meşru olması zararsız olduğu anlamına gelmiyor. Geri yazılan değer, operasyonel sistemin
davranışını değiştirirse, o sistemin ürettiği kayıt da değişir; o kayıt hattın **girdisidir**. Ok
bu noktada bir çembere kapanır. Bu ders çemberi iki sayıyla ölçer: kaç aşama sonra kapandığı ve
kapandıktan sonra bir sonraki koşumun ne verdiği.

- **VA57.** Kod **kurgudur**; hiçbir operasyonel sistem, bulut servisi, satıcı ya da orkestratör
  çağrılmaz. Kaynak M29'un kurgu sayaç okumalarıdır: 200 abone, 12 dönem, 2400 satır, tohum
  20260218.
- **VA58.** Ters ETL tek bir değerle modellenir: **bölge başına beklenen tüketim eşiği**. Sunum
  katmanında hesaplanır, operasyonel sisteme yazılır ve katsayısı 1,2'dir.
- **VA59.** Operasyonel sistemin o eşikle yaptığı şey kurgudur ama sıradandır: saha uygulaması
  eşiği aşan artışı **kaydetmez**, önceki endeksin üstüne eşik kadar ekler ve okumayı doğrulamaya
  bırakır. Kaydedilen değer budur.
- **VA60.** Zincir bir çizge olarak yazılır. **Çizge algoritması tekrarlanmaz**; Veri Yapıları
  kursundaki çizge konusunda ölçüldü. Burada zincir yalnız **yürünür** ve uzunluğu sayılır.
- **VA61.** Koşumlar arasında kaynağın kendisi değişmez. Değişen tek şey operasyonel sistemin
  **kaydettiği** endekstir; gerçek sayaç okumaları sabittir.
- **VA62.** Denetim eşikleri öncekiyle aynıdır: satır sayısı payı 0,05, dağılım payı 0,25.
- **VA63.** Sayılan birimler çevrimdeki aşama, kırpılan okuma, tüketim satırı, kirli özet hücresi,
  sunum sapması ve **koşumlar arası fark**tır. Süre yazılmaz.
- **VA64.** Kursun kuralı bu derste doğrudan sınanır: bir hattın sayısı, yeniden koşturulduğunda
  **aynı sonucu vermesidir**.

## Çemberin Uzunluğu

Aşağıdaki blok ortak tanımı kurar, üzerine üç şey ekler: zinciri yürüyen `cevrim`, operasyonel
sistemin kaydını üreten `al` ve sunum katmanından eşiği yazan `geri_yaz`. Sonra hattı beş kez
koşturur; her koşum bir öncekinin yazdığı eşikle başlar.

```python
# KURGUDUR. Gercek bir operasyonel sistem , bulut servisi ya da orkestrator
# cagrilmaz; olcum aginin sayac okumalari kurgudur , tohum 20260218.
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():                                  # her donem her abone icin bir okuma
    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):                              # donem farkindan tuketim
    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
        cikti.append(dict(k, m3=int(k["endeks"]) - int(onceki["endeks"])))
    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 basina donem ortalamasi
    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


ZINCIR = {"al": "ayikla", "ayikla": "tekille", "tekille": "tuketim",
          "tuketim": "ozet", "ozet": "sun", "sun": "geri_yaz", "geri_yaz": "al"}


def cevrim(bas):
    """Zinciri yurur ve baslangica donene kadar gecilen asamalari toplar."""
    yol, u = [bas], ZINCIR[bas]
    while u != bas:
        yol.append(u)
        u = ZINCIR[u]
    return yol


def al(ham, esik):
    """KURGU operasyonel sistem: esigi asan artisi kaydetmez , esik kadar ekler."""
    kayit, son, kirpilan = [], {}, 0
    for k in ham:
        e, onceki, s = k["endeks"], son.get(k["abone"]), esik.get(k["bolge"])
        if onceki is not None and s is not None and e - onceki > s:
            e = onceki + s
            kirpilan += 1
        son[k["abone"]] = e
        kayit.append(dict(k, endeks=e))
    return kayit, kirpilan


def hat(kayit):
    v, _ = a1_ayikla(kayit)
    v, _ = a2_tekille(v)
    v, _ = a3_tuketim(v)
    oz, _ = a4_ozet(v)
    sun, _ = a5_sun(oz)
    return v, oz, sun


def geri_yaz(v, kat=1.2):
    """Ters ETL: bolge basina beklenen tuketim esigi operasyonel sisteme yazilir."""
    top, say = {}, {}
    for k in v:
        top[k["bolge"]] = top.get(k["bolge"], 0) + k["m3"]
        say[k["bolge"]] = say.get(k["bolge"], 0) + 1
    return {b: int(round(kat * top[b] / say[b])) for b in top}


ham = kaynak_uret()
yol = cevrim("al")
_, TABAN, TSUN = hat(al(ham, {})[0])
print("cevrim:", " -> ".join(yol), "-> al")
print("cevrimdeki asama sayisi", len(yol), ", taban tuketim 2200 , ozet hucresi", len(TABAN))
print()
print("kosum  kirpilan  esik dogu   merkez    kuzey     dogu     bati    guney  onceki farki")
esik, onceki = {}, None
for i in range(1, 6):
    kayit, kirp = al(ham, esik)
    v, oz, sun = hat(kayit)
    f = "-" if onceki is None else max(abs(round(sun[b] - onceki[b], 2)) for b in sun)
    print(f"{i:>5} {kirp:>9} {esik.get('dogu', 0):>10}  " +
          " ".join(f"{sun[b]:>8}" for b in ("merkez", "kuzey", "dogu", "bati", "guney")) +
          f" {f:>12}")
    onceki, esik = sun, geri_yaz(v)
```

```
cevrim: al -> ayikla -> tekille -> tuketim -> ozet -> sun -> geri_yaz -> al
cevrimdeki asama sayisi 7 , taban tuketim 2200 , ozet hucresi 55

kosum  kirpilan  esik dogu   merkez    kuzey     dogu     bati    guney  onceki farki
    1         0          0   1321.45  1212.55   881.36   833.09  1065.55            -
    2      1129         31   1274.45  1177.73   853.45   813.82  1033.09         47.0
    3      1207         30   1263.55  1167.45   845.55   813.82  1025.36         10.9
    4      1225         30   1263.55  1153.09   845.55   813.82  1025.36        14.36
    5      1225         30   1263.55  1153.09   845.55   813.82  1025.36          0.0
```

## Yedi Aşama Sonra Kendi Girdisi

İlk satır çemberi veriyor. Zincir `al` düğümünden çıkıyor, hattın beş aşamasını geçiyor, ters ETL
yazımına giriyor ve oradan **yeniden `al`'a** dönüyor: **yedi aşama**. Bu sayının kendisi bir uyarı
değildir; uyarı olan, zincirin artık bir **çizge çevrimi** olmasıdır. Ters ETL eklenmeden önce
zincir altı düğüm ve beş kenardı, başı ile sonu belliydi. Yedinci kenar eklendiği anda hiçbir düğüm
"önce çalışır" olmaktan çıkıyor; her düğümün bir öncülü var.

Bunun pratikteki karşılığı, hattın artık **koşumdan bağımsız** bir tanımının olmamasıdır. "Hattın
çıktısı nedir" sorusunun cevabı bir sayı değil, bir **koşum numarasıdır**. Tablonun son sütunu bunu
sayıyor: ikinci koşum birinciden 47,00, üçüncü ikinciden 10,90, dördüncü üçüncüden 14,36 sapıyor.
Aynı kaynakla, aynı kodla, aynı tohumla koşan hat üç kez üç ayrı cevap veriyor.

Mekanizma orta sütunlarda okunuyor. Birinci koşum eşiksiz koşuyor ve doğru cevabı veriyor; sonunda
doğu bölgesi için 31 eşiğini operasyonel sisteme yazıyor. İkinci koşumda saha uygulaması bu eşiği
kullanıyor ve **1129 okumayı** kırpıyor: eşiği aşan artışlar kaydedilmiyor. Kırpılmış okumalarla
hesaplanan ortalama düşüyor, düşen ortalama daha küçük bir eşik üretiyor, küçülen eşik üçüncü
koşumda **1207** okumayı kırpıyor. Döngü kendi kendini besliyor ve her turda girdiyi biraz daha
daraltıyor.

Yedinci kenarın nerede durduğuna dikkat etmek gerekir: hattın kodunda değil. Hat yalnız bir değer
yazar ve orada biter; kırpma kararı operasyonel sistemin içindedir. Çevrim iki sistemin arasında
kurulur ve **hiçbirinin kodunda görünmez**. Hattın çizgesine bakan biri altı düğümlü, düzgün bir
zincir görür; saha uygulamasına bakan biri makul bir doğrulama kuralı görür. Çemberi ancak ikisini
aynı anda çizen biri görebilir.

## Döngünün Durduğu Yer

Beşinci satır döngünün durduğunu söylüyor: kırpılan okuma 1225'te sabitleniyor ve koşumlar arası
fark **0,00** oluyor. Dördüncü koşumdan sonra hat yeniden koşturulduğunda **aynı sonucu veriyor**.
Aşağıdaki blok durulan koşumun ne olduğunu ölçüyor ve aynı hattı geri yazımın girdiye dokunmadığı
kurulumda koşturuyor.

```python
kayit, kirp = al(ham, esik)
v, oz, sun = hat(kayit)
print("durulan kosum: tuketim", len(v), ", kirli hucre",
      sum(1 for a in set(oz) | set(TABAN) if oz.get(a) != TABAN.get(a)))
print("tabandan sunum sapmasi", {b: round(sun[b] - TSUN[b], 2) for b in TSUN})
print("en buyuk ozet hucresi sapmasi",
      round(max(abs(oz[a] - TABAN[a]) / abs(TABAN[a]) for a in TABAN), 4), "< esik 0.25")

print()
print("geri yazilan esik girdiye dokunmuyor:")
print("kosum  kirpilan   merkez    kuzey     dogu     bati    guney  onceki farki")
esik, onceki = {}, None
for i in range(1, 4):
    kayit, kirp = al(ham, {})
    v, oz, sun = hat(kayit)
    f = "-" if onceki is None else max(abs(round(sun[b] - onceki[b], 2)) for b in sun)
    print(f"{i:>5} {kirp:>9}  " +
          " ".join(f"{sun[b]:>8}" for b in ("merkez", "kuzey", "dogu", "bati", "guney")) +
          f" {f:>12}")
    onceki, esik = sun, geri_yaz(v)
print("operasyonel sisteme yazilan esik", esik)
```

```
durulan kosum: tuketim 2200 , kirli hucre 55
tabandan sunum sapmasi {'merkez': -57.9, 'kuzey': -59.46, 'dogu': -35.81, 'bati': -19.27, 'guney': -40.19}
en buyuk ozet hucresi sapmasi 0.1788 < esik 0.25

geri yazilan esik girdiye dokunmuyor:
kosum  kirpilan   merkez    kuzey     dogu     bati    guney  onceki farki
    1         0   1321.45  1212.55   881.36   833.09  1065.55            -
    2         0   1321.45  1212.55   881.36   833.09  1065.55          0.0
    3         0   1321.45  1212.55   881.36   833.09  1065.55          0.0
operasyonel sisteme yazilan esik {'merkez': 32, 'kuzey': 32, 'dogu': 31, 'bati': 32, 'guney': 32}
```

İlk üç satır durulan koşumun ne olduğunu söylüyor ve cevap rahatsız edicidir. Tüketim satırı
**2200**, yani taban değeriyle birebir aynı; hiçbir satır düşmemiş, hiçbir satır çoğalmamıştır.
Buna karşılık 55 özet hücresinin **55'i** kirlidir: her bölgenin her dönemi yanlış hesaplanmıştır.
Sunum −19,27 ile −59,46 arasında sapmıştır. Ve hiçbir denetim ateşlemez: satır sayısı tamdır,
şema tamdır, anahtarlar tekildir, her bölge her dönemde vardır ve en büyük hücre sapması **0,1788**
ile 0,25 payının altındadır.

Bu tablo kursun kuralının nasıl okunması gerektiğini de düzeltiyor. Dördüncü koşumdan sonra hat
yeniden koşturulduğunda aynı sonucu veriyor, yani kural sağlanıyor — ama sonuç yanlış. Kural bir
**gerek** koşuldur, yeter koşul değil: yeniden koşturulamayan hat ölçülmemiştir, yeniden
koşturulabilen hat ise ancak **kendi çıktısını yeniden okumuyorsa** ölçülmüştür. Döngülü hatta
kararlılık, doğruluğun değil **yakınsamanın** işaretidir; hat kendi ürettiği kısıtla dengeye
gelmiştir.

Bu bozulmayı görebilecek tek denetim, birinci tablonun son sütununda zaten duruyor: aynı dönemin
sunum değerini bir önceki koşumunkiyle karşılaştıran bir denetim. O denetim ikinci, üçüncü ve
dördüncü koşumda ateşlerdi, çünkü sırasıyla 47,00, 10,90 ve 14,36 fark görürdü. Beşinci koşumdan
sonra ise **susardı**. Yani koşum karşılaştırması bir döngüyü ancak **oturmadan önce** yakalar;
oturduktan sonra hattın bütün göstergeleri yeşildir ve sunulan değer kalıcı olarak yanlıştır. Bir
döngü, yakalanma penceresi kendi kendine kapanan tek bozulma biçimidir.

İkinci tablo çözümü gösteriyor ve çözüm ters ETL'den vazgeçmek değildir. Eşik yine hesaplanıyor,
yine operasyonel sisteme yazılıyor — merkez 32, kuzey 32, doğu 31, batı 32, güney 32 — ama saha
uygulaması onu **kaydı değiştirmek için** değil yalnız doğrulamaya çağırmak için kullanıyor. Ham
okuma olduğu gibi saklanıyor. Kırpılan okuma **0**, koşumlar arası fark **0,00** ve üç koşum da
tabanı veriyor. Ters ETL bir çıktıdır; hattın girdisi olduğu anda çıktı olmaktan çıkar. Ayrımı
kuran şey değerin yazılıp yazılmaması değil, **geri yazılan alanın hattın okuduğu alan olup
olmamasıdır**.

## Özet

- Ters ETL, işlenmiş verinin operasyonel sisteme geri yazılmasıdır ve geri yazılan değer o sistemin
  ürettiği kaydı etkiliyorsa hattın zinciri çembere kapanır: `al` düğümünden çıkan yol yedi aşama
  sonra kendi girdisine döner.
- Birinci koşumun yazdığı eşik ikinci koşumda 1129, üçüncüde 1207, dördüncüde 1225 okumayı kırpıyor;
  aynı kaynak ve aynı kodla koşumlar arası fark 47,00, 10,90 ve 14,36 çıkıyor.
- Döngü dördüncü koşumda duruyor ama durduğu yer taban değildir: tüketim satırı 2200'de kalırken
  55 özet hücresinin 55'i kirleniyor ve sunum −19,27 … −59,46 sapıyor.
- Bu bozulmayı hiçbir denetim yakalamıyor; satır sayısı, şema, tekillik ve bölüm bütünlüğü tamdır
  ve en büyük hücre sapması 0,1788 ile 0,25 payının altında kalır.
- Koşumları karşılaştıran bir denetim döngüyü ikinci, üçüncü ve dördüncü koşumda görürdü; beşinciden
  sonra susardı. Bir döngünün yakalanma penceresi kendi kendine kapanır.
- Aynı eşik hesaplanıp yazıldığı hâlde ham kayda dokunmadığında kırpılan okuma 0, koşumlar arası
  fark 0,00 olur: belirleyici olan değerin yazılması değil, hattın kendi çıktısını okuyup okumadığıdır.

## Sonraki Adım

Altı derste veri hatta **alındı**. Alma yönteminin taşıdığı satır ile kaçırdığı değişiklik sayıldı,
kaynağın kısıtı altında tamamlanan çağrı ölçüldü, mesajın hangi bölümden geleceği ve bölüm sayısının
sıraya ne yaptığı yazıldı, pencere kararının geç gelen kayıtta değiştirdiği sonuç ile durum taşımanın
bedeli çıkarıldı, üç teslim kipinin kaybı ve yinelenmesi ayrı ayrı sayıldı, geri yazımın açtığı
çember ölçüldü. Hepsinin ortak yanı şudur: **satır hatta girdi**. Girdikten sonra ne hâle getirildiği
hiç sorulmadı. Bütün bu derslerde hattın beş aşaması hazır bir kutu gibi çağrıldı; hangi dönüşümün
nerede yapılacağı, aynı hesabın kaynakta mı hedefte mi yürütüleceği, ham satırın hangi katmana kadar
saklanacağı ve bir dönüşümün **doğru** olup olmadığının nasıl yazılacağı tanımlanmadı. Sonraki konu
bunu yapar: dönüştürmenin yerini seçer, katmanları ayırır ve her katmanın hangi bozulmayı
durdurabildiğini sayar.
