Ders 06 / 12
Meta Veri Kataloğu
Bir veri varlığını bulmak için bakılan giriş sayısının katalog varken ve yokken sayılması: on iki varlık ve 119 dosyalık bir kümede beş arama katalogsuz 295, katalogla 29 giriş bakıyor ve en pahalı arama 117'den 11'e iniyor. Katalog bayatladığında sayı geri döner: üç varlık değişince on iki girişin üçü artık var olmayan bir düzeni gösteriyor, aynı beş arama katalogsuz 406, bayat katalogla 251 oluyor, fakat iki arama katalogsuz olandan pahalıya bitiyor (129'a karşı 122 ve 104'e karşı 100), çünkü ölü giriş taranıyor ve ardından tam tarama yine yapılıyor.
İçindekiler
Önceki iki ders bir küme varlık biriktirdi: bir merkezî ambar, birim odaklı alt kümeler ve her biri kendi bölüm anahtarını seçmiş birim ürünleri. Her ölçümde sorunun hangi depoya gideceği zaten biliniyordu; maliyet, adres bilindikten sonra başlıyordu. Gerçekte o adres bir yerde yazılı değilse bulunmaz. Bir birimin ürününün adı, sahibi, taşıdığı sütunlar, bölüm anahtarı ve hangi dönemleri kapsadığı yazılmamışsa, bir soruyu yanıtlayacak varlığı bulmanın kendisi bir arama işidir.
Bu dersin ölçtüğü şey o aramadır. Meta veri kataloğu (metadata catalog) varlık başına tek bir giriş tutar ve arama o girişler üzerinde yapılır; katalog yoksa arama varlıkların dosyaları üzerinde yapılır. İki durumda bakılan giriş sayısı sayılır. Ardından kataloğun kendi kusuru ölçülür: depolama tarafı değiştiğinde kaç giriş artık var olmayan bir düzeni gösteriyor ve bu girişlere güvenen arama ne kadara mal oluyor.
- DY61. Kaynak, hat, depolama düzeni ve katalog kurgudur ve ders içinde tanımlanır. Hiçbir ambar, göl, katalog ürünü ya da sorgu motoru çağrılmaz. Tohum 20260218.
- DY62. Bakılan giriş iki türlüdür ve ikisi de tek tek sayılır. Katalogsuz aramada bir varlığın neyi kapsadığını öğrenmek için dosyalarının açılması gerekir; bakılan giriş açılan dosyadır. Katalogla aramada bakılan giriş taranan katalog girişidir.
- DY63. Varlıklar ada göre sıralı taranır. Arama, göreve yeten ilk varlıkta durur; en ucuz varlığı seçme kararı bu dersin ölçüsünün dışındadır.
- DY64. Katalog girişi yazıldığı andaki düzeni taşır. Depolama tarafındaki bir değişiklik girişe kendiliğinden yansımaz; yansıması ayrı bir iştir.
- DY65. Katalogla yapılan arama girişe güvenir ama doğrular: eşleşen girişin varlığı gerçekten göreve yetmiyorsa arama katalogsuz aramaya düşer ve iki bedel toplanır.
- DY66. Soyağacı ölçüsü Veri Mühendisliğine Giriş kursundaki Veri Soyağacı dersinde ölçüldü; burada tekrarlanmaz. Soyağacının nesnesi bir satırın dayandığı satırlardır; kataloğun nesnesi bir varlığın nerede durduğudur. Biri değeri açıklar, öbürü adresi verir.
Katalog Varken ve Yokken
Küme on iki varlıktan oluşur. Merkezî ambar bütün bölgeleri ve tarife sütununu taşır ama saklama penceresi yüzünden yalnız son altı dönemi tutar. Beş bölge pazarı bütün dönemleri taşır, tarife sütununu taşımaz. Bir tarife pazarı işyeri satırlarını bütün bölgelerden toplar. Beş birim ürünü kendi bölgesinin bütün satırlarını, kendi seçtiği anahtarla saklar. Beş arama görevi bu küme üzerinde koşar.
# KURGUDUR. Olcum aginin sayac okumalari, hat ve depolama duzeni ders icinde # tanimlanir; hicbir ambar, gol, katalog urunu ya da sorgu motoru 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): 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 cikti.append(dict(k, m3=int(k["endeks"]) - int(onceki["endeks"]))) return cikti, dusen def hattan(kaynak): v, _ = a1_ayikla(kaynak) v, _ = a2_tekille(v) v, _ = a3_tuketim(v) return v def yaz(kayitlar, bolumleme=()): duzen = {} for k in kayitlar: duzen.setdefault(tuple(k[a] for a in bolumleme), []).append(k) return duzen TUM = hattan(kaynak_uret()) SON6 = sorted({k["donem"] for k in TUM})[-6:] TAM = ("abone", "donem", "bolge", "tip", "m3") BOLGESEL = ("abone", "donem", "bolge", "m3") # tarife sutunu tasinmiyor AGIN_ANAHTARI = {"dogu": ("donem",), "bati": ("donem", "tip"), "kuzey": (), "guney": ("donem",), "merkez": ("tip",)} def varlik(ad, sahip, kayitlar, anahtar, sutun): """Bir veri varligi: satirlari , bolumleme anahtari ve tasidigi sutunlar.""" duzen = yaz(kayitlar, anahtar) return {"ad": ad, "sahip": sahip, "anahtar": anahtar, "sutun": sutun, "dosya": len(duzen), "satir": {(k["abone"], k["donem"]) for k in kayitlar}, "bolge": {k["bolge"] for k in kayitlar}, "tip": {k["tip"] for k in kayitlar}, "donem": {k["donem"] for k in kayitlar}} def kurulum(): """Onceki iki dersin biriktirdigi varliklar , ada gore siralanmis.""" v = [varlik("ambar_merkezi", "merkez ekibi", [k for k in TUM if k["donem"] in SON6], ("donem",), TAM)] for b in BOLGE: v.append(varlik(f"pazar_{b}", f"{b} raporlama", [k for k in TUM if k["bolge"] == b], ("donem",), BOLGESEL)) v.append(varlik("pazar_tarife", "tarife ekibi", [k for k in TUM if k["tip"] == "isyeri"], ("donem",), TAM)) for b in BOLGE: v.append(varlik(f"urun_{b}", f"{b} birimi", [k for k in TUM if k["bolge"] == b], AGIN_ANAHTARI[b], TAM)) return sorted(v, key=lambda x: x["ad"]) def gereken(gorev): return {(k["abone"], k["donem"]) for k in TUM if all(k[a] == d for a, d in gorev.items())} def gercekte_kapsiyor(v, gorev): """Varligin kendisine bakarak: istenen satirlarin hepsi burada mi.""" return set(gorev) <= set(v["sutun"]) and gereken(gorev) <= v["satir"] def kayda_gore_kapsiyor(g, gorev): """Yalnizca katalog girisine bakarak , dosya acmadan.""" if not set(gorev) <= set(g["sutun"]): return False if gorev["donem"] not in g["donem"] or gorev["bolge"] not in g["bolge"]: return False return {gorev["tip"]} <= g["tip"] if "tip" in gorev else g["tip"] == set(TIP) def katalog_yaz(varliklar): """Varlik basina tek giris: ad , sahip , anahtar , dosya , sutun , kapsam.""" return [{a: v[a] for a in ("ad", "sahip", "anahtar", "dosya", "sutun", "bolge", "tip", "donem")} for v in varliklar] def katalogsuz_ara(varliklar, gorev): """Sirayla her varligin dosyalari acilir; bakilan giris = acilan dosya.""" bakilan = 0 for v in varliklar: bakilan += v["dosya"] if gercekte_kapsiyor(v, gorev): return bakilan, v["ad"] return bakilan, None def kataloglu_ara(varliklar, katalog, gorev): """Girisler taranir; eslesen girisin varligi dogrulanir. Bulunamazsa katalogsuz aramaya dusulur ve iki maliyet toplanir.""" ada_gore = {v["ad"]: v for v in varliklar} for i, g in enumerate(katalog, 1): if not kayda_gore_kapsiyor(g, gorev): continue v = ada_gore.get(g["ad"]) if v is not None and gercekte_kapsiyor(v, gorev): return i, g["ad"], False bakilan, ad = katalogsuz_ara(varliklar, gorev) return i + bakilan, ad, True return len(katalog), None, False GOREV = [("kuzey / 2026-03 / isyeri", {"bolge": "kuzey", "donem": "2026-03", "tip": "isyeri"}), ("guney / 2026-02", {"bolge": "guney", "donem": "2026-02"}), ("bati / 2026-11 / mesken", {"bolge": "bati", "donem": "2026-11", "tip": "mesken"}), ("merkez / 2026-02", {"bolge": "merkez", "donem": "2026-02"}), ("kuzey / 2026-05 / mesken", {"bolge": "kuzey", "donem": "2026-05", "tip": "mesken"})] VARLIK = kurulum() KATALOG = katalog_yaz(VARLIK) print(f"varlik {len(VARLIK)} , dosya {sum(v['dosya'] for v in VARLIK)} , " f"katalog girisi {len(KATALOG)}\n") print("varlik sahip anahtar dosya donem sutun") for v in VARLIK: print(f"{v['ad']:<17} {v['sahip']:<17} {str(v['anahtar']):<19} {v['dosya']:>4}" f" {len(v['donem']):>4} {len(v['sutun']):>4}") print("\ngorev katalogsuz kataloglu bulunan varlik") t1 = t2 = 0 for ad, g in GOREV: b1, v1 = katalogsuz_ara(VARLIK, g) b2, v2, _ = kataloglu_ara(VARLIK, KATALOG, g) t1, t2 = t1 + b1, t2 + b2 print(f"{ad:<27} {b1:>10} {b2:>9} {v1}") print(f"{'toplam':<27} {t1:>10} {t2:>9}")
varlik 12 , dosya 119 , katalog girisi 12
varlik sahip anahtar dosya donem sutun
ambar_merkezi merkez ekibi ('donem',) 6 6 5
pazar_bati bati raporlama ('donem',) 11 11 4
pazar_dogu dogu raporlama ('donem',) 11 11 4
pazar_guney guney raporlama ('donem',) 11 11 4
pazar_kuzey kuzey raporlama ('donem',) 11 11 4
pazar_merkez merkez raporlama ('donem',) 11 11 4
pazar_tarife tarife ekibi ('donem',) 11 11 5
urun_bati bati birimi ('donem', 'tip') 22 11 5
urun_dogu dogu birimi ('donem',) 11 11 5
urun_guney guney birimi ('donem',) 11 11 5
urun_kuzey kuzey birimi () 1 11 5
urun_merkez merkez birimi ('tip',) 2 11 5
gorev katalogsuz kataloglu bulunan varlik
kuzey / 2026-03 / isyeri 72 7 pazar_tarife
guney / 2026-02 39 4 pazar_guney
bati / 2026-11 / mesken 6 1 ambar_merkezi
merkez / 2026-02 61 6 pazar_merkez
kuzey / 2026-05 / mesken 117 11 urun_kuzey
toplam 295 29
Aradaki oran on kattır: beş arama katalogsuz 295, katalogla 29 giriş baktırıyor. Farkın kaynağı ölçek değil birimdir. Katalogsuz arama varlık başına o varlığın bütün dosyalarını açar, çünkü bir varlığın hangi dönemleri ya da hangi tarifeleri kapsadığını bilmenin başka yolu yoktur; katalogla arama varlık başına tek giriş okur. On iki varlık 119 dosya tutuyor, katalog aynı kümeyi 12 girişle anlatıyor. Katalog bir dizin değildir ve sorguyu hızlandırmaz; varlık sayısı ile dosya sayısı arasındaki oranı aramaya kazandırır.
Görevler arasındaki dağılım da okunmalıdır. En ucuz arama batı için olandır: merkezî ambar hem
tarife sütununu taşır hem de o dönemi kapsar ve sıralamada ilk varlıktır. En pahalısı kuzeyin
2026-05 dönemidir: ambar saklama penceresi yüzünden düşer, beş bölge pazarı tarife sütununu
taşımadığı için düşer, tarife pazarı yalnız işyerini tuttuğu için düşer ve arama on birinci
varlığa kadar sürer — katalogsuz 117 dosya, katalogla 11 giriş. Bir varlığı bulmanın bedelini
kümenin büyüklüğü değil, aranan şeyin sıradaki yeri belirler; katalogun yaptığı o sırayı dosya
biriminden giriş birimine çevirmektir.
Katalogun Bayatlaması
Katalog yazıldığı andaki düzeni taşır. Depolama tarafı durmaz: bir pazar kaldırılır, bir birim ürününü yeniden bölümler, bir pazara saklama penceresi uygulanır. Bu üç değişiklik girişlere kendiliğinden yansımaz. Aşağıdaki koşum önce kaç girişin yanlışlandığını sayar, sonra aynı beş aramayı eski katalogla yeni küme üzerinde tekrarlar.
# Onceki blogun tanimlari surer: VARLIK, KATALOG, GOREV, varlik, TUM, SON6, TAM, # BOLGESEL, katalogsuz_ara, kataloglu_ara. def duzen_degisti(varliklar): """Katalog yazildiktan sonra depolama tarafinda olan uc degisiklik.""" yeni = [] for v in varliklar: if v["ad"] == "pazar_tarife": # varlik kaldirildi continue if v["ad"] == "urun_kuzey": # yeniden bolumlendi yeni.append(varlik(v["ad"], v["sahip"], [k for k in TUM if k["bolge"] == "kuzey"], ("donem", "tip"), TAM)) elif v["ad"] == "pazar_guney": # saklama penceresi daraldi yeni.append(varlik(v["ad"], v["sahip"], [k for k in TUM if k["bolge"] == "guney" and k["donem"] in SON6], ("donem",), BOLGESEL)) else: yeni.append(v) return yeni YENI = duzen_degisti(VARLIK) ada_gore = {v["ad"]: v for v in YENI} print("bayat giris kayitli anahtar / dosya / donem gercek anahtar / dosya / donem") bayat = 0 for g in KATALOG: v = ada_gore.get(g["ad"]) if v is not None and all(g[a] == v[a] for a in ("anahtar", "dosya", "donem")): continue bayat += 1 gercek = ("varlik yok" if v is None else f"{str(v['anahtar']):<18} {v['dosya']:>3} {len(v['donem']):>3}") print(f"{g['ad']:<14} {str(g['anahtar']):<18} {g['dosya']:>3} {len(g['donem']):>3}" f" {gercek}") print(f"\n{len(KATALOG)} girisin {bayat} tanesi artik var olmayan bir duzeni gosteriyor.") print("\ngorev katalogsuz kataloglu geri dusme bulunan varlik") t1 = t2 = 0 for ad, gor in GOREV: b1, v1 = katalogsuz_ara(YENI, gor) b2, v2, dus = kataloglu_ara(YENI, KATALOG, gor) t1, t2 = t1 + b1, t2 + b2 print(f"{ad:<27} {b1:>10} {b2:>9} {'evet' if dus else 'hayir':>10} {v2}") print(f"{'toplam':<27} {t1:>10} {t2:>9}")
bayat giris kayitli anahtar / dosya / donem gercek anahtar / dosya / donem
pazar_guney ('donem',) 11 11 ('donem',) 6 6
pazar_tarife ('donem',) 11 11 varlik yok
urun_kuzey () 1 11 ('donem', 'tip') 22 11
12 girisin 3 tanesi artik var olmayan bir duzeni gosteriyor.
gorev katalogsuz kataloglu geri dusme bulunan varlik
kuzey / 2026-03 / isyeri 122 129 evet urun_kuzey
guney / 2026-02 100 104 evet urun_guney
bati / 2026-11 / mesken 6 1 hayir ambar_merkezi
merkez / 2026-02 56 6 hayir pazar_merkez
kuzey / 2026-05 / mesken 122 11 hayir urun_kuzey
toplam 406 251
Üç değişiklik on iki girişin üçünü yanlışladı ve üçü aynı türden değil. urun_kuzey girişi hâlâ
var olan bir varlığı gösteriyor; yanlış olan yalnız kayıtlı anahtar ile dosya sayısı, bir yerine
yirmi iki. Bu giriş aramayı bozmuyor, maliyet kestirimini bozuyor: o varlığa gideceğini bilen
bir taraf bir dosyaya dokunacağını sanıyor. pazar_guney girişi on bir dönem vaat ediyor, varlık
altı dönem taşıyor. pazar_tarife girişi hiç olmayan bir varlığı gösteriyor. Bir katalog
girişinin yeşil olması o düzenin ölçüldüğü anlamına gelmez, ve yanlışlığın üç ayrı derecesi
vardır: eksik kestirim, eksik kapsam, hiç yokluk.
Son tablo bunun aramaya ne yaptığını gösteriyor. Katalog toplamda hâlâ kazandırıyor, 406’ya karşı
251. Ama iki satırda kazanç eksiye dönüyor. Kuzeyin 2026-03 araması yedi giriş tarıyor, ölü
girişe gidiyor, varlığı bulamıyor ve baştan tam taramaya düşüyor: 129, oysa katalog hiç olmasa
122. Güneyin 2026-02 araması dört giriş tarıyor, girişin vaat ettiği dönemi varlıkta bulamıyor
ve aynı yolu izliyor: 104, katalogsuz 100. Fark küçük ama işareti önemlidir; bayat bir giriş
aramanın önüne bir yanlış adres koyar ve o adres denenmeden elenemez. Kataloğun bedeli girişleri
yazmak değil, girişleri düzenle aynı hızda tazelemektir.
Özet
- Meta veri kataloğu varlık başına tek giriş tutar: ad, sahip, bölüm anahtarı, dosya sayısı, sütunlar ve kapsanan dönem ile bölge. Bir dizin değildir; sorguyu değil aramayı ucuzlatır.
- On iki varlık ve 119 dosyalık kümede beş arama katalogsuz 295, katalogla 29 giriş baktırır; kazanç varlık sayısı ile dosya sayısı arasındaki orandan gelir.
- Bir aramanın bedelini kümenin büyüklüğü değil aranan varlığın sıradaki yeri belirler: en ucuz arama 6’ya karşı 1, en pahalı arama 117’ye karşı 11 giriş bakar.
- Üç değişiklik on iki girişin üçünü yanlışlar ve üç ayrı derecede: eksik kestirim (dosya sayısı 1 yerine 22), eksik kapsam (on bir dönem yerine altı) ve hiç yokluk.
- Bayat katalogla aynı beş arama 406’ya karşı 251 giriş baktırır, ama iki arama katalogsuz olandan pahalıya biter: 129’a karşı 122 ve 104’e karşı 100.
- Kataloğun bedeli girişleri yazmak değil, girişleri düzenle aynı hızda tazelemektir; tazelenmeyen giriş aramanın önüne yanlış bir adres koyar.
Sonraki Adım
Altı derste verinin nerede durduğu ayrıldı: şemaya uyan yer ile ham yer, ikisini bir arada tutan düzen, alt küme çıkarmanın kazandırdığı ve çoğalttığı, sahipliğin dağıtılmasının iki sayısı ve varlığı bulmanın giriş cinsinden bedeli. Bütün bu ölçümlerin ortak bir sessiz varsayımı vardı: satır hep aynı biçimde duruyordu — abone, dönem, bölge, tarife ve tüketim yan yana, tek bir düz sıra hâlinde. O biçim hiç sorgulanmadı. Oysa bir dosyaya yazılan şey bir satır listesi değil, bir tablo şeklidir; hangi alanların ölçüm hangilerinin niteleme olduğu, aynı nitelemenin kaç kez tekrarlandığı ve bir niteleme zaman içinde değiştiğinde eski değerinin saklanıp saklanmadığı ayrı kararlardır. Sonraki konu bu kararları ölçer: aynı veri, aynı yer, farklı şekil.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.