---
title: 'Geriye Dönük Doldurma'
source: 'https://academia.sh/tr/kurslar/veri-hatlari/geriye-donuk-doldurma'
course: 'Veri Hatları ve Orkestrasyon'
language: tr
updated: '2026-08-17T18:08:50+00:00'
license: 'CC BY-SA 4.0'
---

# Geriye Dönük Doldurma

Değişen bir kuralın geçmiş dönemlere uygulanmasının sayılması: kural on iki dönemin tamamına uygulandığında 12 dönem ve 2200 satır yeniden hesaplanıyor, yalnız iki döneme uygulandığında 2 dönem ve 400 satır yeterli oluyor ama rapor tam uygulamadan 16,98 ile 29,57 arasında sapıyor. Karışık rapor altı beklentinin hiçbirini bozmuyor, kendi içinde tutarlı çıkıyor ve kuralın hücrede yarattığı yüzde 2,75'lik sıçrama doğal dönem oynaklığının ortancasının altında kaldığı için hiçbir denetime takılmıyor. Sapmanın kaynağı veri değil hangi dönemlerin yeniden hesaplandığıdır; satıra kural sürümü damgalandığında karışıklık tek bir karşılaştırmayla görünür oluyor.

Bir önceki dersin son bloğu işyeri tüketimini 1,05 katsayıyla raporlayan bir kural yazdı ve altı
beklentinin hiçbiri bozulmadı. Beklentiler haklıydı, çünkü ortada bir bozulma yoktu: kural kasıtlı
olarak değişmişti. Orada kapatılmayan soru şuydu — kural bugünden itibaren geçerliyse, **eski
kuralla hesaplanmış on bir dönem** ne olacak.

Bu ders o soruyu ölçer. Bütün dönemleri yeniden hesaplamak koşum bedeli demektir; yalnız birkaç
dönemi yeniden hesaplamak ise raporun bir kısmını yeni, kalanını eski kuralla bırakır. İkinci
seçenek ucuzdur, hızlıdır ve ortaya çıkardığı rapor **kendi içinde tutarlı görünür**. Bu kursun
ikinci iddiasının en net örneği budur.

- **DN49.** Kaynak ve beş aşamalı hat **kurgudur**; gerçek bir depo, dönüştürme çerçevesi ya da
  orkestratör çağrılmaz. Tohum **20260218**, rapor koşumdan bağımsızdır.
- **DN50.** **Geri doldurma (backfill)**, değişen bir kuralın ya da düzeltilen bir verinin **geçmiş
  dönemlere** uygulanıp o dönemlerin yeniden hesaplanmasıdır. Ölçülen şey hangi dönemlerin
  yeniden hesaplandığıdır.
- **DN51.** Kural değişikliği bir bozulma değil **karardır**: işyeri tüketimi 1,00 yerine 1,05
  katsayıyla raporlanacak. Yeni kural doğru kabul edilir; tartışılan şey kapsamıdır.
- **DN52.** Taban çizgisi **geri doldurmasız koşumdur**: hiçbir geçmiş dönem yeniden hesaplanmaz,
  rapor bütünüyle eski kuralla durur.
- **DN53.** Yeniden işleme ile yinelemeye dayanıklılık Veri Mühendisliğine Giriş kursunda **satır
  düzeyinde** ölçüldü ve **tekrarlanmaz**; burada ölçülen **dönem düzeyidir**.
- **DN54.** Bedel **dönem** ve **satır** olarak yazılır, ham süre yazılmaz.
- **DN55.** Tüketim dönem farkından hesaplandığı için bir dönemi yeniden hesaplamak **bir önceki
  dönemin** kaynağını da okumayı gerektirir; pencere kaynakta bir dönem geniştir.
- **DN56.** Çözünürlük: tüketim satırı **2200**, özet **55 hücre**, sunum **5 değer**. **Sunum
  üzerinde oran basılmaz**, değerin kendisi yazılır.

## Geri Doldurmanın Kapsam Sorusu

Bir kural değiştiğinde üç seçenek vardır ve üçü de savunulabilir. **Hiç geri doldurmamak** raporu
tutarlı bırakır ama bugünden öncesini yanlış kuralla anlatır. **Tümünü geri doldurmak** raporun
tamamını yeni kurala taşır ve on iki dönemin hepsini yeniden hesaplatır. **Kısmen geri doldurmak**
en ucuzudur ve genellikle bir gerekçesi de vardır: yalnız denetlenen dönemler, yalnız açık kalan
çeyrek, yalnız veri hâlâ elde olan pencere.

Kısmi seçeneğin sorunu bedelinde değil **görünmezliğindedir**. Ortaya çıkan rapor iki kuralın
birleşimidir, ama satırların hiçbiri hangi kuralla hesaplandığını taşımaz. Aşağıdaki blok kaynağı,
beş aşamayı ve kuralı seçilen dönemlere uygulayan geri doldurma işlevini kurar.

```python
# KURGUDUR. Olcum aginin sayac okumalari ve bes asamali hat ders icinde
# tanimlanir; gercek bir depo, cerceve ya da orkestrator cagrilmaz.
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):
    """Zorunlu alanlari tasimayan satir dusurulur."""
    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. Onceki donem yoksa satir hesaplanamaz."""
    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):
    """Sunum: 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


def geri_doldur(kayitlar, donemler, kural_yeni=True):
    """Kural degisti: isyeri tuketimi 1,00 yerine 1,05 katsayiyla raporlanacak.
    Yalnizca secilen donemler yeniden hesaplanir."""
    v, _ = a1_ayikla(kayitlar)
    v, _ = a2_tekille(v)
    v, _ = a3_tuketim(v)
    yeni = []
    for k in v:
        kat = 1.05 if (kural_yeni and k["donem"] in donemler and k["tip"] == "isyeri") else 1.0
        yeni.append(dict(k, m3=k["m3"] * kat))
    oz, _ = a4_ozet(yeni)
    sun, _ = a5_sun(oz)
    return sun
```

## Üç Rapor ve İki Bedel

İkinci blok aynı kaynaktan üç rapor üretir: kural hiç uygulanmamış, on iki dönemin tamamına
uygulanmış ve yalnız `2026-07` ile `2026-08` dönemlerine uygulanmış. Ardından iki geri doldurma
penceresinin bedeli sayılır.

```python
PENCERE = ["2026-07", "2026-08"]
KAYNAK = kaynak_uret()


def fark(a, b):
    return {k: round(a[k] - b[k], 2) for k in a}


ESKI = geri_doldur(KAYNAK, [], kural_yeni=False)
TAM = geri_doldur(KAYNAK, DONEM)
KARISIK = geri_doldur(KAYNAK, PENCERE)
print("eski kural     :", ESKI)
print("tam uygulama   :", TAM)
print("iki donem      :", KARISIK)
print("karisik - tam  :", fark(KARISIK, TAM))
print("karisik - eski :", fark(KARISIK, ESKI))


def bedel(donemler):
    """Yeniden hesaplanan donem , yazilan tuketim satiri , okunan kaynak donemi ve satiri."""
    i = min(DONEM.index(d) for d in donemler)
    okunan = sorted(set(donemler) | {DONEM[max(i - 1, 0)]})
    yazilan = 200 * sum(1 for d in donemler if d != DONEM[0])
    return len(donemler), yazilan, len(okunan), 200 * len(okunan)


print()
print(f"{'pencere':<13}{'donem':>7}{'yazilan':>9}{'okunan donem':>14}{'okunan satir':>14}")
for ad, dl in (("tum donemler", DONEM), ("iki donem", PENCERE)):
    print(f"{ad:<13}" + "".join(f"{x:>{w}}" for x, w in zip(bedel(dl), (7, 9, 14, 14))))
```

```
eski kural     : {'merkez': 1321.45, 'kuzey': 1212.55, 'dogu': 881.36, 'bati': 833.09, 'guney': 1065.55}
tam uygulama   : {'merkez': 1357.32, 'kuzey': 1235.57, 'dogu': 902.13, 'bati': 859.22, 'guney': 1095.81}
iki donem      : {'merkez': 1327.75, 'kuzey': 1216.36, 'dogu': 885.15, 'bati': 837.77, 'guney': 1070.65}
karisik - tam  : {'merkez': -29.57, 'kuzey': -19.21, 'dogu': -16.98, 'bati': -21.45, 'guney': -25.16}
karisik - eski : {'merkez': 6.3, 'kuzey': 3.81, 'dogu': 3.79, 'bati': 4.68, 'guney': 5.1}

pencere        donem  yazilan  okunan donem  okunan satir
tum donemler      12     2200            12          2400
iki donem          2      400             3           600
```

Bedel tablosu kısmi seçeneğin neden seçildiğini gösterir: iki dönemlik pencere **2 dönem** ve
**400 satır** yeniden hesaplarken tam uygulama **12 dönem** ve **2200 satır** hesaplıyor. Okunan
kaynak sütunu dönemler arası bağımlılığın bedelidir: iki dönemi yeniden hesaplamak için **üç
dönemin** kaynağı okunuyor, çünkü `2026-07` tüketimi `2026-06` endeksine dayanır. Pencere kaynakta
her zaman bir dönem geniştir ve bu genişlik pencerenin başında ödenir.

Sapma satırı dersin ana sayısıdır. Karışık rapor tam uygulamadan **−16,98 ile −29,57 arasında**
sapıyor; beş bölgenin hiçbiri tam uygulamanın verdiği değerde değil. Karşılığında karışık rapor
eski kuraldan da farklı — beş değerin hepsi **3,79 ile 6,30 arasında** yukarıda. Yani ortaya çıkan
rapor **ne eski kuralın raporudur ne yeni kuralın**; üçüncü bir şeydir ve o üçüncü şeyin
karşılığında gerçek dünyada hiçbir kural yoktur.

Sapmanın kaynağı veri değildir. Üç raporun tamamı aynı 2400 kaynak satırından, aynı beş aşamayla
üretildi; hiçbir satır kaybolmadı, hiçbir satır bozulmadı. Farkı yaratan tek şey **hangi dönemlerin
yeniden hesaplandığıdır**.

## Karışık Rapor Hangi Denetimden Geçiyor

Üçüncü blok karışık raporu bir önceki dersin altı beklentisiyle sınar, raporun kendi içinde tutarlı
olup olmadığına bakar ve kuralın hücrede yarattığı sıçramayı bölgenin **doğal dönem oynaklığıyla**
karşılaştırır. Bu son karşılaştırma en iyimser durumu temsil eder: bir gözlemci raporu dönem dönem
inceleyip sıçrama arasa ne görürdü.

```python
import statistics


def yeniden_hesapla(kayitlar, donemler):
    """Ayni kural , iki fark: satirlar donuyor ve her satira kural surumu damgalaniyor."""
    v, _ = a1_ayikla(kayitlar)
    v, _ = a2_tekille(v)
    v, _ = a3_tuketim(v)
    return [dict(k, kural="v2" if k["donem"] in donemler else "v1",
                 m3=k["m3"] * (1.05 if (k["donem"] in donemler and k["tip"] == "isyeri") else 1.0))
            for k in v]


def beklentiler(v):
    """Bir onceki dersin alti beklentisi , donusumun kendi ciktisi uzerinde."""
    oz = a4_ozet(v)[0]
    ad = [(k["abone"], k["donem"]) for k in v]
    d = {"anahtar_tekil": len(ad) != len(set(ad)),
         "negatif_yok": any(k["m3"] < 0 for k in v),
         "tavan": any(k["m3"] > 200 for k in v),
         "satir_orani": abs(len(v) - 2200) / 2200 > 0.02,
         "hucre_tamligi": len(oz) != 55, "oynaklik": False}
    for b in BOLGE:
        h = [x for (bb, _), x in oz.items() if bb == b]
        if any(abs(x - statistics.median(h)) / statistics.median(h) > 0.30 for x in h):
            d["oynaklik"] = True
    return [a for a, s in d.items() if s], oz


BOZULAN, OZ_KAR = beklentiler(yeniden_hesapla(KAYNAK, PENCERE))
OZ_ESKI = a4_ozet(yeniden_hesapla(KAYNAK, []))[0]
print("karisik raporda bozulan beklenti:", BOZULAN or "yok")
print("rapor kendi icinde tutarli mi:",
      all(abs(KARISIK[b] - round(sum(x for (bb, _), x in OZ_KAR.items() if bb == b) / 11, 2)) < 0.01
          for b in BOLGE))
for b in ("merkez", "dogu"):
    dogal = [abs(OZ_ESKI[(b, DONEM[i])] - OZ_ESKI[(b, DONEM[i - 1])]) / OZ_ESKI[(b, DONEM[i - 1])]
             for i in range(2, 12)]
    kural = [(OZ_KAR[(b, d)] - OZ_ESKI[(b, d)]) / OZ_ESKI[(b, d)] for d in PENCERE]
    print(f"{b:<7} dogal degisim ortanca={statistics.median(dogal):.4f} "
          f"en buyuk={max(dogal):.4f}  kuralin sicramasi={max(kural):.4f}")
```

```
karisik raporda bozulan beklenti: yok
rapor kendi icinde tutarli mi: True
merkez  dogal degisim ortanca=0.0883 en buyuk=0.1874  kuralin sicramasi=0.0275
dogu    dogal degisim ortanca=0.0909 en buyuk=0.1541  kuralin sicramasi=0.0234
```

Üç satır aynı şeyi söyler: **hiçbir denetim bunu bildirmiyor.** Altı beklentinin hiçbiri bozulmuyor,
çünkü bozulacak bir şey yok — satır sayısı 2200, hücre sayısı 55, anahtarlar tekil, hiçbir değer
eksi ya da tavanın üstünde. Rapor kendi içinde tutarlı: her bölgenin sunum değeri kendi on bir özet
hücresinin ortalamasına eşit. Kaynağa bakan denetimler de sessiz kalır, çünkü kaynak hiç
değişmemiştir.

Son iki satır en iyimser gözlemciyi de eler. Kuralın hücrede yarattığı en büyük sıçrama merkezde
**yüzde 2,75**, doğuda **yüzde 2,34**; oysa aynı bölgelerin doğal dönem değişiminin **ortancası**
yüzde 8,83 ve yüzde 9,09, en büyüğü yüzde 18,74 ve yüzde 15,41. Kuralın izi doğal oynaklığın
ortancasının bile üçte biri kadar. Dönem dönem bakan bir gözlemci sıçramayı arasa da bulamaz, çünkü
sıçrama gürültünün içindedir.

İki koşumun da kendi içinde tutarlı görünmesi bu dersin çekirdeğidir. Ne tam uygulama ne kısmi
uygulama bir hata üretir; ikisi de sonuna kadar koşar, ikisi de temiz bir rapor basar. Aralarındaki
tek fark bir liste — hangi dönemlerin yeniden hesaplandığı — ve o liste raporun hiçbir yerinde
yazmaz.

## Kural Sürümü Damgası

Dördüncü blok eksik olanı ekler. `yeniden_hesapla` her satıra hangi kuralla hesaplandığını yazıyor;
raporda kaç sürüm bulunduğuna bakmak yeterli olur. Aynı blok kursun kuralını da sınar: geri doldurma
iki kez koşturulduğunda ne oluyor.

```python
V_TAM = yeniden_hesapla(KAYNAK, DONEM)
V_KAR = yeniden_hesapla(KAYNAK, PENCERE)
for ad, v in (("tam", V_TAM), ("karisik", V_KAR)):
    s = sorted(set(k["kural"] for k in v))
    print(f"{ad:<8} kural surumu={str(s):<14} raporda tek surum mu:", len(s) == 1)
print("kaynaktan iki kez kosuldu:",
      geri_doldur(KAYNAK, PENCERE) == geri_doldur(KAYNAK, PENCERE))
yamali = [dict(k, m3=k["m3"] * (1.05 if k["donem"] in PENCERE and k["tip"] == "isyeri" else 1.0))
          for k in V_KAR]
print("cikti uzerine ikinci kez:", fark(a5_sun(a4_ozet(yamali)[0])[0], KARISIK))
```

```
tam      kural surumu=['v2']         raporda tek surum mu: True
karisik  kural surumu=['v1', 'v2']   raporda tek surum mu: False
kaynaktan iki kez kosuldu: True
cikti uzerine ikinci kez: {'merkez': 6.62, 'kuzey': 4.0, 'dogu': 3.98, 'bati': 4.92, 'guney': 5.35}
```

Damga tek bir alandır ve karışıklığı tek bir karşılaştırmaya indirir: raporda iki sürüm varsa rapor
karışıktır. Bedeli de tek bir alandır, 2200 satırın her birine yazılan bir dize. Damganın yazılma
anı önemlidir; hesap yapıldıktan sonra hangi satırın hangi kuralla üretildiği geriye dönük
çıkarılamaz, çünkü satırda kalan tek şey sonucun kendisidir.

Son iki satır kursun kuralını iki yönden gösterir. Geri doldurma **kaynaktan** hesaplandığında iki
kez koşturmak sonucu değiştirmez; işlev **yinelemeye dayanıklıdır** ve rapor koşum sayısından
bağımsızdır. Aynı düzeltme **çıktının üzerine yama** olarak uygulandığında ikinci koşum katsayıyı
bir kez daha çarpar ve rapor 3,98 ile 6,62 arasında bir kez daha kayar. İki yol da aynı sonucu
hedefler, biri yeniden koşturulabilir, öbürü yalnızca **bir kez** doğrudur — ve hangisinin
koşulduğunu rapora bakarak ayırt etmenin yolu yoktur.

## Özet

- Geri doldurma kapsam kararıdır: tam uygulama 12 dönem ve 2200 satır yeniden hesaplatırken iki
  dönemlik pencere 2 dönem ve 400 satırla yetiniyor, ama kaynakta **üç dönem** okunuyor çünkü
  tüketim bir önceki dönemin endeksine dayanır.
- Kısmi geri doldurmanın raporu tam uygulamadan **−16,98 ile −29,57 arasında** sapıyor ve eski
  kuraldan da 3,79 ile 6,30 arasında ayrılıyor; ortaya çıkan rapor iki kuralın hiçbirine ait değil.
- Sapmanın kaynağı veri değil **hangi dönemlerin yeniden hesaplandığıdır**; üç rapor da aynı 2400
  kaynak satırından, tek satır kaybetmeden üretiliyor.
- Karışık rapor altı beklentinin hiçbirini bozmuyor, kendi içinde tutarlı çıkıyor ve kuralın
  hücrede yarattığı en büyük sıçrama (yüzde 2,75) doğal dönem oynaklığının ortancasının (yüzde
  8,83) çok altında kaldığı için dönem dönem bakan gözlemciye de görünmüyor.
- Satıra kural sürümü damgalandığında karışıklık tek bir karşılaştırmayla görünür oluyor; geri
  doldurma kaynaktan hesaplandığında yinelemeye dayanıklıdır, çıktı üzerine yama olarak
  uygulandığında ikinci koşum raporu 3,98 ile 6,62 arasında bir kez daha kaydırır.

## Sonraki Adım

On bir derste hat kuruldu: veri altı ayrı yoldan alındı, kaybının ve yinelenmesinin sunuma ne
yaptığı sayıldı, dönüşümün nerede yapılacağı, hangi sırayla koşacağı, hangi katmanda duracağı,
nasıl sınanacağı ve geçmişe nasıl uygulanacağı yazıldı. Bu on bir dersin tamamında hattı çalıştıran
tek şey vardı: **bir insanın elle verdiği başlatma kararı**. Hangi görevin ne zaman koşacağı, bir
görev düştüğünde ardındakilerin ne yapacağı, aynı işin iki kez tetiklenip tetiklenmediği ve bu
dersin kural sürümü damgasını **kimin yazacağı** hiç sorulmadı. Sonraki konu hattı bir görev
çizgesine çevirir ve çizgenin şeklinin bir başarısızlığı nereye kadar taşıdığını ölçer.
