İçeriğe geç
academia.sh

Ders 06 / 16

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.

İçindekiler

Ö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ı farktı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.

# 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.

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.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat