İçeriğe geç
academia.sh

Ders 01 / 16

Alma Türleri

Üç alma yönteminin taşıdığı satır ile kaçırdığı değişikliğin yan yana sayılması: dönem başına dört görevden kurulu çizge 48 düğüm ve 47 kenar taşıyor, tam yükleme on iki koşumda 15.560 satır taşıyıp hiçbir değişikliği kaçırmıyor, artımlı yükleme 2.360 satır taşıyıp 148 değişikliği kaçırıyor, değişiklik yakalama 2.508 satır taşıyıp hiçbirini kaçırmıyor. Artımlı yüklemenin kaçırdığı 40 geç gelen satır ile 108 düzeltilmemiş satır sunumu her bölgede aşağı çekiyor, ama satır sayısı denetimi 0,0167 oranıyla sessiz kalıyor ve bozulmayı ancak dağılım denetimi 0,3469 ile aşama 4'te yakalıyor.

İçindekiler

Önceki kurs on iki derste verinin nerede ve hangi düzende durduğunu ölçtü: bölümleme, dosya düzeni, sıkıştırma ve okunan hücre yan yana sayıldı. O düzeni kimin, ne zaman ve hangi sırayla doldurduğu hiç sorulmadı. Bir hat kendiliğinden dolmaz; her dönem birileri onu tetikler, adımlar bir sırayla koşar ve o sıradan biri düştüğünde geri kalanın ne yapacağı önceden yazılmış olmalıdır.

Bu kurs hattı koşum üzerinden ölçer ve kuralı şudur: bir hattın sayısı bir kez doğru koşması değil, yeniden koşturulduğunda aynı sonucu vermesidir; yeniden koşturulamayan hat ölçülmemiş sayılır. Her derste üç sayı yan yana durur: orkestrasyonsuz taban, orkestrasyonlu kurulum ve bedel. Bu ders üçlüyü ve hattın görev çizgesini kurar, sonra ilk soruyu sorar: kaynaktan veri hangi yöntemle alınıyor ve o yöntem neyi kaçırıyor.

  • VA1. Kod kurgudur; gerçek bir depo, motor, mesaj sistemi ya da orkestratör çağrılmaz. Kaynak bir ölçüm ağının kurgu sayaç okumalarıdır: 200 abone, 12 dönem, 2400 satır, tohum 20260218.
  • VA2. Hat belirlenimcidir; rastgelelik kitaplığı kullanılmaz ve bütün sayılar koşumdan bağımsızdır.
  • VA3. Taban çizgisi orkestrasyonsuz koşumdur: tek elle tetikleme, yeniden deneme yok, atomik yazım yok, geri doldurma yok.
  • VA4. Görev çizgesi dönem başına dört görev (task) taşır: al, ayikla, tuketim, ozet. tuketim bir önceki dönemin ayikla görevine de bağlıdır.
  • VA5. Geç gelen satır K01’in gec_gelen bozulmasıdır: 2026-07 döneminin 40 satırı o dönemin koşumunda yoktur, bir sonraki koşumdan önce gelir. Saldırı değil, üretici tarafı kazasıdır.
  • VA6. Ana veri düzeltmesi 12 abonenin bölgesini onuncu koşumdan önce düzeltir ve düzeltme o abonelerin bütün dönemlerine uygulanır.
  • VA7. Hedef anahtarlıdır: (abone, donem) çifti bir satırı tekler, aynı anahtar yeniden yazıldığında üzerine yazılır. Yazım bu yüzden yinelemeye dayanıklıdır (idempotent).
  • VA8. Taşınan satır, al görevinin on iki koşum boyunca hatta geçirdiği satır sayısının toplamıdır. Satır oranının adımı 1/2400, yani 0,0004; sunum üzerinde oran basılmaz.

Hattın Görev Çizgesi

Bir hat, birbirine bağlı görevlerden kurulu bir yönlü çevrimsiz çizgedir (directed acyclic graph). Çizge kavramı ve topolojik sıralama Veri Yapıları kursundaki Çizgeler konusunda ölçüldü; burada algoritma tekrarlanmaz, çizge kurulur ve kullanılır. Dönem başına dört görev vardır ve tek gerçek incelik şudur: tüketim bir fark hesabıdır, bu yüzden tuketim görevi kendi döneminin ayikla görevine olduğu kadar bir önceki dönemin ayikla görevine de bağlıdır. Zincirin dönemler arasına uzanması, ilerideki derslerde bir görev düştüğünde neden bütün bir kuyruğun beklediğini açıklar.

# KURGUDUR. Gercek bir depo, motor 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


# ---- HAT: bes asama, her asama kendi dusurdugu satiri sayar.
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 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 okuma_sonucu(kayitlar):
    v, _ = a1_ayikla(kayitlar)
    v, _ = a2_tekille(v)
    v, _ = a3_tuketim(v)
    oz, _ = a4_ozet(v)
    sun, _ = a5_sun(oz)
    return sun, len(v), oz


# ---- KURGU gorev cizgesi: donem basina dort gorev.
GOREV = ("al", "ayikla", "tuketim", "ozet")
BAGIMLILIK = {"al": (), "ayikla": ("al",), "tuketim": ("ayikla",), "ozet": ("tuketim",)}


def cizge():
    """`tuketim` bir onceki donemin `ayikla`sina da baglidir."""
    dugum, kenar = [], []
    for d in DONEM:
        for g in GOREV:
            dugum.append((g, d))
            for o in BAGIMLILIK[g]:
                kenar.append(((o, d), (g, d)))
        i = DONEM.index(d)
        if i > 0:
            kenar.append((("ayikla", DONEM[i - 1]), ("tuketim", d)))
    return dugum, kenar


def sirala(dugum, kenar):
    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


dugum, kenar = cizge()
sira = sirala(dugum, kenar)
ham = kaynak_uret()
sun, n, _ = okuma_sonucu(ham)
print("cizge", len(dugum), "dugum", len(kenar), "kenar , sira", len(sira), "gorev")
print("ilk uc gorev", sira[:3])
print("kaynak", len(ham), "satir , tuketim", n, "satir")
print("saglam sunum", sun)
cizge 48 dugum 47 kenar , sira 48 gorev
ilk uc gorev [('al', '2026-01'), ('al', '2026-02'), ('al', '2026-03')]
kaynak 2400 satir , tuketim 2200 satir
saglam sunum {'merkez': 1321.45, 'kuzey': 1212.55, 'dogu': 881.36, 'bati': 833.09, 'guney': 1065.55}

Kırk sekiz düğüm, kırk yedi kenar ve tam sıralanabilen bir çizge. Kenar sayısının düğümden bir eksik olması çizgenin tek parça bir orman olduğunu söyler: on iki dönemin al görevleri dışında her düğümün tam bir öncülü vardır. Bu derste ölçülen şey çizgenin şekli değil, en baştaki düğümün ne yaptığıdır — al görevi kaynaktan neyi istiyor.

Üç Alma Yöntemi

Tam yükleme (full load) her koşumda kaynağın o anki tamamını okur ve hedefi baştan yazar. Artımlı yükleme (incremental load) yalnız son alınan dönemden sonraki dönemleri ister; sınır bir dönem numarasıdır ve her koşumda ilerler. Değişiklik yakalama (change data capture) kaynağın kendi değişiklik akışını okur: ekleme ve güncelleme olaylarını taşır, dokunulmayan satırı hiç taşımaz.

Aşağıdaki blok kaynağın zaman içindeki hâlini modelliyor ve üç yöntemi aynı on iki koşumda çalıştırıyor. Kaynağa iki üretici tarafı olayı düşüyor: 2026-07’nin kırk satırı geç geliyor, ve on ikinci abonenin bölgesi onuncu koşumdan önce düzeltiliyor.

# ---- KURGU kaynak sistemin zaman icindeki hali. Iki uretici tarafi olayi:
#  1) K01'in `gec_gelen` bozulmasi: 2026-07'nin 40 satiri o donemin kosumunda
#     yok, bir sonraki kosumdan once geliyor.
#  2) Ana veri duzeltmesi: 12 abonenin bolgesi yanlis girilmis, 10. kosumdan
#     once butun donemleri icin duzeltiliyor.
GEC = [f"A{i:03d}" for i in range(1, 41)]
YANLIS = [f"A{i:03d}" for i in range(101, 113)]


def kaynak_anlik(kosum):
    """Kaynagin `kosum` numarali kosum aninda gorunen hali."""
    kayit = []
    for k in kaynak_uret():
        i = DONEM.index(k["donem"]) + 1
        if i > kosum or (i == 7 == kosum and k["abone"] in GEC):
            continue
        y = dict(k)
        if k["abone"] in YANLIS and kosum < 10:
            y["bolge"] = BOLGE[(BOLGE.index(k["bolge"]) + 1) % 5]
        kayit.append(y)
    return kayit


def tam_yukleme():
    """Her kosumda kaynagin tamami yeniden okunur , hedef silinip yazilir."""
    hedef, tasinan = {}, 0
    for kosum in range(1, 13):
        anlik = kaynak_anlik(kosum)
        tasinan += len(anlik)
        hedef = {(k["abone"], k["donem"]): k for k in anlik}
    return list(hedef.values()), tasinan


def artimli_yukleme():
    """Yalniz son alinan donemden sonraki donemler okunur."""
    hedef, tasinan, sinir = {}, 0, 0
    for kosum in range(1, 13):
        yeni = [k for k in kaynak_anlik(kosum) if DONEM.index(k["donem"]) + 1 > sinir]
        tasinan += len(yeni)
        for k in yeni:
            hedef[(k["abone"], k["donem"])] = k
        sinir = kosum
    return list(hedef.values()), tasinan


def degisiklik_yakalama():
    """Kaynagin degisiklik akisi okunur , ekleme ve guncelleme olaylari tasinir."""
    hedef, tasinan, onceki = {}, 0, {}
    for kosum in range(1, 13):
        anlik = {(k["abone"], k["donem"]): k for k in kaynak_anlik(kosum)}
        olay = [k for ad, k in anlik.items() if onceki.get(ad) != k]
        tasinan += len(olay)
        for k in olay:
            hedef[(k["abone"], k["donem"])] = k
        onceki = anlik
    return list(hedef.values()), tasinan


gercek = {(k["abone"], k["donem"]): k for k in ham}
dogru_sun, _, dogru_oz = okuma_sonucu(ham)
print("yontem      tasinan  hedef  eksik  yanlis  tuketim  satir orani  dagilim eni")
for ad, f in (("tam", tam_yukleme), ("artimli", artimli_yukleme),
              ("degisiklik", degisiklik_yakalama)):
    hed, tasinan = f()
    hd = {(k["abone"], k["donem"]): k for k in hed}
    eksik = len(set(gercek) - set(hd))
    yanlis = sum(1 for a in hd if gercek[a] != hd[a])
    s, t, oz = okuma_sonucu(hed)
    en = max(abs(v - dogru_oz[a]) / max(abs(dogru_oz[a]), 1) for a, v in oz.items())
    print(f"{ad:<11} {tasinan:>7} {len(hd):>6} {eksik:>6} {yanlis:>7} {t:>8} "
          f"{abs(len(hd) - 2400) / 2400:>12.4f} {en:>12.4f}")
print()
for ad, f in (("tam", tam_yukleme), ("artimli", artimli_yukleme),
              ("degisiklik", degisiklik_yakalama)):
    s, _, _ = okuma_sonucu(f()[0])
    print(f"{ad:<11}", {b: round(s.get(b, 0) - dogru_sun[b], 2) for b in dogru_sun})
yontem      tasinan  hedef  eksik  yanlis  tuketim  satir orani  dagilim eni
tam           15560   2400      0       0     2200       0.0000       0.0000
artimli        2360   2360     40     108     2120       0.0167       0.3469
degisiklik     2508   2400      0       0     2200       0.0000       0.0000

tam         {'merkez': 0.0, 'kuzey': 0.0, 'dogu': 0.0, 'bati': 0.0, 'guney': 0.0}
artimli     {'merkez': -11.18, 'kuzey': -28.1, 'dogu': -39.09, 'bati': -36.91, 'guney': -70.0}
degisiklik  {'merkez': 0.0, 'kuzey': 0.0, 'dogu': 0.0, 'bati': 0.0, 'guney': 0.0}

Taşınan Satır ile Kaçırılan Değişiklik

Tablonun ilk sütunu tam yüklemenin bedelini yazıyor: on iki koşumda 15.560 satır taşınmış, oysa sonuçta hedefte duran satır 2400. Aynı veriyi altı buçuk kez taşımanın karşılığı, hiçbir değişikliği kaçırmamasıdır. Geç gelen kırk satır sekizinci koşumda kendiliğinden yerine oturur, bölge düzeltmesi onuncu koşumda bütün dönemlere yayılır, çünkü her koşum kaynağı yeniden okur. Tam yüklemenin bir kusuru yoktur; yalnız pahalıdır ve kaynak büyüdükçe pahalılığı doğrusal büyür.

Artımlı yükleme en az satırı taşıyor: 2360. Bedeli aynı satırda duruyor. Yedinci koşum dönemin yalnız 160 satırını görüyor; kırk satır sonra geliyor ama sınır artık yedidedir ve o satırlar bir daha hiç istenmez. Bölge düzeltmesi de aynı nedenle yalnız onuncu koşumdan sonraki dönemlere iniyor: hedefte on iki abonenin dokuz dönemi, yani 108 satır, eski bölgesiyle kalıyor. Toplam 148 kaçırılan değişiklik, ve bunların 40’ı eksik satır, 108’i yanlış satırdır. Artımlı yükleme neyi kaçırdığını bilmez — sınırın gerisinde bir şeyin değiştiğini görecek bir düzeneği yoktur.

Değişiklik yakalama iki olayı da görüyor ve bunun için taşıdığı satır 2508. Artımlı yüklemeden yalnız 148 satır fazla, tam yüklemeden 13.052 satır az. Fark tam olarak kaçırılan değişiklik sayısı kadardır ve bu tesadüf değildir: değişiklik yakalamanın taşıdığı şey değişikliğin kendisidir. Bedeli satırda değil kaynaktadır; kaynağın değişiklik akışını yayımlıyor olması gerekir, ve bu yayımı yapmayan bir kaynakta yöntem hiç kurulamaz.

Kaçırılan Değişikliği Hangi Denetim Görüyor

Artımlı yüklemenin hedefi sunumu her bölgede aşağı çekiyor: en küçük sapma merkezde −11,18, en büyüğü güneyde −70,00. Bu sapmayı görecek biri var mıdır? Veri Mühendisliğine Giriş kursunda kurulan denetim kümesi bu soruya iki farklı cevap veriyor. Satır sayısı denetiminin oranı 0,0167; öntanımlı tolerans 0,05 olduğu için denetim yeşil kalıyor. Şema, tür ve tekillik denetimleri de yeşildir, çünkü eksik satırların şeması bozuk değil, sadece yokturlar. Bölge kümesi de tamdır: on iki abonenin bölgesi yanlış ama yanlış olan bölge de listede vardır.

Yakalayan tek denetim dağılım denetimidir ve özet katmanında en büyük hücre sapması 0,3469 ile 0,25 eşiğini aşar. Bu denetim aşama 4’te koşar; yani bozulma alma, ayıklama, tekilleştirme ve tüketim hesabından geçtikten sonra görünür. Yakalama gecikmesi 4 aşamadır ve o ana kadar 2120 satırlık ara tablo çoktan yazılmıştır. Yöntem seçimi burada bir ölçü seçimine dönüşür: artımlı yükleme taşınan satırı 6,6 kat düşürür, karşılığında 148 değişikliği kaçırır ve bu kaçağı yalnız en pahalı denetim, en geç aşamada bildirir.

Özet

  • Hat, dönem başına dört görevden kurulu bir yönlü çevrimsiz çizgedir: 48 düğüm, 47 kenar ve tam sıralanabilen bir koşum sırası. tuketim bir önceki dönemin ayikla görevine bağlıdır, bu yüzden zincir dönemler arasına uzanır.
  • Tam yükleme hiçbir değişikliği kaçırmaz ve bedelini taşınan satırla öder: 2400 satırlık bir hedef için on iki koşumda 15.560 satır taşınır.
  • Artımlı yükleme en az satırı taşır (2360) ama sınırın gerisinde olan biteni göremez: 40 geç gelen satır ile 108 düzeltilmemiş satır, toplam 148 değişiklik kaçar.
  • Değişiklik yakalama iki olayı da görür ve artımlı yüklemeden yalnız kaçırılan değişiklik sayısı kadar, 148 satır fazla taşır; koşulu, kaynağın değişiklik akışını yayımlıyor olmasıdır.
  • Kaçırılan değişikliği satır sayısı denetimi 0,0167 oranıyla görmez; yalnız dağılım denetimi 0,3469 ile ve aşama 4 gecikmeyle bildirir.

Sonraki Adım

Bu derste al görevi kaynağı tek bir hamlede okudu: kaynak_anlik çağrıldı ve satırlar elde oldu. Kaynak sistemler böyle okunmaz. Bir uçnokta veriyi sayfa sayfa verir, pencere başına kaç çağrı yapılabileceğini sınırlar ve çağrılardan bir kısmı geçici olarak düşer. Sonraki ders aynı al görevini bu kısıtların altına sokar ve iki şeyi sayar: kısıt altında tamamlanan çağrı ve alınan satır. Ölçülecek takas şudur: sayfa boyunu büyütmek çağrı sayısını düşürür, ama düşen tek bir çağrının kaçırdığı satır aynı oranda büyür.

İ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