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.tuketimbir önceki döneminayiklagörevine de bağlıdır. - VA5. Geç gelen satır K01’in
gec_gelenbozulması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,
algö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ı.
tuketimbir önceki döneminayiklagö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.