Ders 23 / 23
Erişim Denetimi
Arama kümesinin yetki yüzeyi: aynı sorgunun okuyucu, görevli ve kapsamsız anahtar altında döndürdüğü dizin, belge ve alan kümesinin sayılması, belge düzeyi süzmenin puanlamadan önce mi sonra mı uygulandığının ilk on sonuca ve derin sıraya etkisinin ölçülmesi, süzülen belgelerin sayaç üzerinden sızdırdığı bilginin gösterilmesi, kapsamı yazılmamış bir anahtarın eriştiği dizin sayısıyla süresi dolmuş anahtarın yanıtsız bıraktığı sorgunun sayılması ve kursun yirmi üç dersinin küme, sıra ve bedel tablosunda toplanması.
İçindekiler
Önceki ders bir dizinin bütün olarak kopyalanmasını ve yeniden üretilmesini ele aldı; ortak varsayımı, kümeye erişen herkesin bütün dizini görmeye yetkili olduğuydu. Kütüphane kataloğunda bu doğru değildir: bağış koşuluyla kapatılmış kayıtlar, ödünç geçmişi ve edinim yazışmaları aynı kümede durur ama herkese açık değildir. Bu ders kimlik doğrulamayı değil, arama kümesinin yetki yüzeyini ölçer.
Yetki Yüzeyi
Bir rol burada üç şeyin çarpımıdır: erişilebilen dizinler, uygulanan belge süzgeci ve görülen alanlar. Düzenekte üç dizin var — açık katalog, ödünç kayıtları, edinim kaynağı — ve katalog kayıtlarının bir bölümünde yalnız görevlilerin gördüğü bir iç not alanı bulunuyor. Küme yine süreç içi bir modeldir: bir rol yalnızca bu üçlüdür.
AK21 — bağış partisi 1500 kayıttır, tek konudan gelir ve erişimi bağış koşuluyla kısıtlanmıştır. Doğrusal etkilidir: parti büyüdükçe aşağıdaki istatistik sapması büyür. AK22 — ödünç ve kaynak kayıtları ilgili kitabın ad ve konu terimlerini taşır. AK23 — anahtar yüz sorguluk akışın altmışıncısında dolar.
// kume/yetki.mjs — dizin, belge ve alan duzeyinde erisim denetimi. Uretec ve ters dizin onceki // derslerle ayni. Yetki SUREC ICI BIR MODELDIR: kimlik dogrulama yoktur, bir rol yalnizca // (dizinler, belge suzgeci, alanlar) uclusudur. const ORTAK = ["kitap", "yazar", "eser", "metin", "bolum", "baski", "sayfa", "dil", "cilt", "yayin"]; const OZEL = { cocuk: ["masal", "resimli", "okul", "oyun", "hayvan", "cizgi"], oyku: ["kisa", "anlati", "derleme", "gunluk", "yalnizlik", "kasaba"], roman: ["kahraman", "kent", "kusak", "ev", "yolculuk", "mektup"], tarih: ["imparatorluk", "belge", "arsiv", "savas", "yuzyil", "vakayiname"], gezi: ["deniz", "yol", "harita", "sehir", "liman", "gemi"], siir: ["dize", "olcu", "imge", "ses", "sessizlik", "kafiye"], deneme: ["dusunce", "elestiri", "okuma", "zaman", "not", "soylesi"], bilim: ["olcum", "deney", "kuram", "veri", "gozlem", "denklem"], }; const NADIR = ["fener", "kuyu", "ipek", "kule", "bahce", "kar", "ada", "koru", "tas", "cinar", "kirlangic", "demirci", "pusula", "kehribar"]; const KONU = Object.keys(OZEL); function derlem({ adet = 4000, tohum = 20260731 } = {}) { let s = tohum % 2147483647; const r = () => (s = (s * 48271) % 2147483647) / 2147483647; const sec = (a) => a[Math.floor(r() * a.length)], belge = []; for (let i = 1; i <= adet; i += 1) { const konu = sec(KONU), oz = OZEL[konu], soz = [sec(oz), sec(NADIR)]; if (r() < 0.5) soz.push(sec(ORTAK)); for (let j = 0, n = 10 + Math.floor(r() * 7); j < n; j += 1) soz.push(r() < 0.45 ? sec(ORTAK) : r() < 0.85 ? sec(oz) : sec(NADIR)); belge.push({ id: i, konu, yil: 1990 + Math.floor(r() * 36), metin: [soz[0], soz[1], konu, ...soz.slice(2)].join(" ") }); } return belge; } function dizinle(belge) { const gonderi = new Map(), uzunluk = new Map(); for (const d of belge) { const t = d.metin.split(" "), sayim = new Map(); for (const x of t) sayim.set(x, (sayim.get(x) ?? 0) + 1); uzunluk.set(d.id, t.length); for (const [x, n] of sayim) { if (!gonderi.has(x)) gonderi.set(x, []); gonderi.get(x).push([d.id, n]); // gonderi girisi: kimlik + siklik } } const ort = [...uzunluk.values()].reduce((a, b) => a + b, 0) / (belge.length || 1); return { gonderi, uzunluk, N: belge.length, ort }; } // Puanlama: terim sikligi, ters belge sikligi ve uzunluk. Puan, ISTATISTIGI HANGI DIZIN // VERIYORSA ondan gelir; dersin ikinci olcumu tam olarak bu secimi karsilastirir. function ara(dz, terim, k) { const N = dz.N, ort = dz.ort, puan = new Map(); let taranan = 0; for (const t of terim) { const g = dz.gonderi.get(t) ?? [], df = g.length; const idf = Math.log(1 + (N - df + 0.5) / (df + 0.5)); for (const [id, tf] of g) { taranan += 1; const norm = tf + 1.2 * (0.25 + 0.75 * dz.uzunluk.get(id) / ort); puan.set(id, (puan.get(id) ?? 0) + idf * tf * 2.2 / norm); } } const sirali = [...puan].sort((a, b) => b[1] - a[1] || a[0] - b[0]).slice(0, k); return { aday: sirali.map(([id, p]) => ({ id, p })), taranan, eslesen: puan.size }; } const K = 10, AKIS = 100, OMUR = 60, KISITLI = 1500; const SORGU = ["oyku", "fener", "kitap", "bagis"]; // bagis kaydi olan, adinda fener gecen oyku kitabi const s = (x, n) => String(x).padStart(n); // Katalog: 4000 acik kayit + bagis kosuluyla kisitli, tek konudan gelen bir parti (ayri tohum, // kimlikler 4000 sonrasina tasinir). Odunc ve kaynak ayri dizinlerdir. const ACIK = derlem({ adet: 4000 }); const KATALOG = [...ACIK, ...derlem({ adet: 20000, tohum: 20260801 }).filter((d) => d.konu === "oyku") .slice(0, KISITLI).map((d, i) => ({ ...d, id: 4001 + i, kisitli: true }))]; const ODUNC = derlem({ adet: 900, tohum: 20260901 }).map((d) => ({ ...d, id: 20000 + d.id })); const KAYNAK = derlem({ adet: 400, tohum: 20261001 }).map((d) => ({ ...d, id: 30000 + d.id })); // Ic not alani: edinim yazismasi, kendi sozlugu ve tohumu var. const NOT_SOZ = ["bagis", "kosul", "sart", "edinim", "satin", "alma", "yazisma", "fatura", "vasiyet"]; let n = 20261101; const r = () => (n = (n * 48271) % 2147483647) / 2147483647; for (const d of KATALOG) if (r() < 0.35) d.not = Array.from({ length: 3 + Math.floor(r() * 4) }, () => NOT_SOZ[Math.floor(r() * 9)]).join(" "); // Bir (belge kumesi, alan) cifti icin dizin; "not" alaninda yalnizca notu olan belge vardir. const kur = (belge, alan) => dizinle(alan === "not" ? belge.filter((d) => d.not).map((d) => ({ id: d.id, metin: d.not })) : belge); // Sorgu her (dizin, alan) ciftinde puanlanir ve puanlar toplanir; suz belge duzeyi denetimidir. // ham suzmeden onceki eslesmedir: sayaca bu yazilirsa kisitli belgeler disari sizar. function sor(dizinler, terim, suz = () => true) { const puan = new Map(); let taranan = 0, ham = 0; for (const dz of dizinler) { const c = ara(dz, terim, Infinity); taranan += c.taranan; ham += c.eslesen; for (const a of c.aday) if (suz(a.id)) puan.set(a.id, (puan.get(a.id) ?? 0) + a.p); } const y = [...puan].sort((a, b) => b[1] - a[1] || a[0] - b[0]).map(([id]) => id); return { tum: y, ilk: y.slice(0, K), eslesen: y.length, taranan, ham }; } const ortak = (a, b) => a.filter((x) => b.includes(x)).length; console.log(`katalog ${KATALOG.length} belge (4000 acik + ${KISITLI} bagis kosuluyla kisitli), odunc ${ODUNC.length}, kaynak`); console.log(`${KAYNAK.length}, not alani ${KATALOG.filter((d) => d.not).length} kayitta. Tohum 20260731 ve 20261101. Sorgu "oyku fener kitap bagis".\n`); console.log("rol / anahtar | dizin | belge | alan | yanitlanan | taranan giris | eslesen | ilk 3 sonuc"); console.log("----------------------|-------|-------|------------|------------|---------------|---------|------------------"); for (const [ad, kume, izin, alan, yanit] of [ ["okuyucu", [KATALOG], (d) => !d.kisitli, ["metin"], AKIS], ["gorevli", [KATALOG, ODUNC], () => true, ["metin", "not"], AKIS], ["gorevli, not kapali", [KATALOG, ODUNC], () => true, ["metin"], AKIS], ["kapsamsiz anahtar", [KATALOG, ODUNC, KAYNAK], () => true, ["metin", "not"], AKIS], ["suresi dolmus anahtar", [], () => true, [], OMUR], ]) { const c = sor(kume.flatMap((x) => alan.map((a) => kur(x.filter(izin), a))), SORGU); console.log(`${ad.padEnd(21)} | ${s(kume.length, 5)} | ${s(kume.reduce((t, x) => t + x.filter(izin).length, 0), 5)} | ` + `${(alan.join(", ") || "-").padEnd(10)} | ${s(`${yanit}/${AKIS}`, 10)} | ${s(c.taranan, 13)} | ${s(c.eslesen, 7)} | ${c.ilk.slice(0, 3).join(" ") || "-"}`); } const once = sor([kur(ACIK, "metin")], SORGU); const sonra = sor([kur(KATALOG, "metin")], SORGU, (id) => id <= 4000); console.log("\nbelge duzeyi suzme (okuyucu rolu, iki uygulama, ayni 4000 acik kayit):"); console.log("uygulama | istatistigi veren kume | eslesen | raporlanan sayac | ilk 10 ortak | yer degistiren belge"); for (const [ad, kume, c, sayac] of [["once suz", "izinli 4000 kayit", once, once.eslesen], ["sonra suz", "tam katalog 5500", sonra, sonra.ham]]) { console.log(`${ad.padEnd(9)} | ${kume.padEnd(23)} | ${s(c.eslesen, 7)} | ${s(sayac, 16)} | ` + `${s(ortak(c.ilk, once.ilk) + "/10", 12)} | ${s(c.tum.filter((x, i) => once.tum[i] !== x).length, 20)}`); } console.log(`ilk 10, once suz : ${once.ilk.join(" ")}`); console.log(`ilk 10, sonra suz: ${sonra.ilk.join(" ")}`); console.log(`\nkosumdan bagimsiz: kapsami yazilmamis anahtar en yetkili rolle ayni ucluyu alir ve` + ` suresi dolmus anahtar ${AKIS - OMUR} sorguyu yanitsiz birakir.`);
katalog 5500 belge (4000 acik + 1500 bagis kosuluyla kisitli), odunc 900, kaynak 400, not alani 1931 kayitta. Tohum 20260731 ve 20261101. Sorgu "oyku fener kitap bagis". rol / anahtar | dizin | belge | alan | yanitlanan | taranan giris | eslesen | ilk 3 sonuc ----------------------|-------|-------|------------|------------|---------------|---------|------------------ okuyucu | 1 | 4000 | metin | 100/100 | 2998 | 2463 | 1613 3589 2806 gorevli | 2 | 6400 | metin, not | 100/100 | 6882 | 4743 | 4551 4589 5265 gorevli, not kapali | 2 | 6400 | metin | 100/100 | 6130 | 4542 | 20332 20557 20765 kapsamsiz anahtar | 3 | 6800 | metin, not | 100/100 | 7175 | 4986 | 4551 4589 5265 suresi dolmus anahtar | 0 | 0 | - | 60/100 | 0 | 0 | - belge duzeyi suzme (okuyucu rolu, iki uygulama, ayni 4000 acik kayit): uygulama | istatistigi veren kume | eslesen | raporlanan sayac | ilk 10 ortak | yer degistiren belge once suz | izinli 4000 kayit | 2463 | 2463 | 10/10 | 0 sonra suz | tam katalog 5500 | 2463 | 3963 | 7/10 | 1433 ilk 10, once suz : 1613 3589 2806 493 1188 1100 3214 308 476 1012 ilk 10, sonra suz: 1613 3589 2806 493 1188 3127 1100 3214 3695 3561 kosumdan bagimsiz: kapsami yazilmamis anahtar en yetkili rolle ayni ucluyu alir ve suresi dolmus anahtar 40 sorguyu yanitsiz birakir.
Üç Düzeyde Aynı Sorgu
Birinci tablo tek bir soruyu beş yetki altında koşturuyor. Okuyucu tek dizine ve 4000 açık kayda erişip 2463 belge alıyor; görevli iki dizine ve 6400 kayda erişiyor, eşleşen 4743’e çıkıyor ve ilk üç sonucun üçü de değişiyor. Kümeyi büyüten yalnız izin değil, izinle gelen başka dizinlerin aynı sıraya girmesidir.
Üçüncü satır alan düzeyini yalıtıyor: aynı görevli, aynı iki dizin, aynı 6400 kayıt, tek fark not alanının kapatılması. Eşleşen 4542’ye iniyor — 201 kayıt yalnızca not alanından eşleşiyordu — ve ilk üç, katalogdan ödünç kayıtlarına geçiyor. Bir alanı kapatmak listeden belge silmekle kalmaz, kalanların puan bileşenlerinden birini de siler.
Dördüncü satır varsayılan açık kurulumdur: kapsamı yazılmamış anahtar üç dizine ve 6800 kayda erişiyor, hiçbir role verilmemiş bir genişlik alıyor ve taranan girişi 7175’e çıkarıyor. Beşincisi süreyi gösteriyor: süresi dolmuş anahtar yüz sorgunun kırkını yanıtsız bırakıyor.
Süzmenin Puanlamaya Sızması
İkinci tablo dersin asıl ölçümüdür. Okuyucu rolü iki biçimde uygulanabilir: kısıtlı 1500 kayıt ya baştan dizinin dışında tutulur (önce süz), ya da tam katalog üzerinden puanlanıp listeden atılır (sonra süz). İkisi de aynı 2463 belgeyi döndürüyor — küme birebir aynı.
Sıra aynı değil. İlk on sonucun yalnız yedisi ortak: altıncı sırada 3127, dokuzuncu ve onuncuda
3695 ile 3561 beliriyor, buna karşılık 308, 476 ve 1012 listeden düşüyor; derin sırada 2463
belgenin 1433’ü yer değiştirmiş. Sebep tek bir sayıdır: ters belge sıklığı. Sonra süzen kurulumda
oyku terimi 5500 belgede sayılıyor ve kısıtlı parti tek konudan geldiği için o terimin ayırt
ediciliği düşüyor. Okuyucunun göremeyeceği belgeler, görebildiği belgelerin sırasını belirliyor.
Aynı kurulum bilgi de sızdırıyor: raporlanan sayaç önce süzende 2463, sonra süzende 3963 ve aradaki 1500 kısıtlı partinin tam boyudur — sayaç okuyucuya göremediği kayıtların sayısını söylüyor. Süzmenin puanlamadan önce mi sonra mı uygulandığı bir başarım ayrıntısı değildir: hem sırayı hem sızıntıyı belirler.
Özet
- Yetki üç ayrı kesme yapar: okuyucu 1 dizin ve 4000 kayıtla 2463, görevli 2 dizin ve 6400 kayıtla 4743 belge aldı; ilk üç sonuç tümüyle değişti. Not alanı kapatılınca eşleşen 4542’ye indi.
- Kapsamı yazılmamış anahtar üç dizine ve 6800 kayda erişti, taranan girişi 2998’den 7175’e çıkardı; süresi dolmuş anahtar yüz sorgunun kırkını yanıtsız bıraktı.
- Belge düzeyi süzme kümeyi değiştirmeden sırayı değiştirdi: aynı 2463 belgede ilk onun yalnız yedisi ortaktı, 1433 belge yer değiştirdi ve sayaç kısıtlı 1500 kaydı sızdırdı.
Kurs Kapanışı
| Ders | Değişen küme | Değişen sıra | Bedel |
|---|---|---|---|
| Motor ve Veritabanı Farkı | LIKE 68, dizin 12 | plan düzeni, kimlik düzeni | 124.863 → 1.076 bayt |
| Ters Dizin | konum 23 → 10 | gönderi listesi kimlik sırasında | kesişim 19.622 → 470 |
| Çözümleyici Zinciri | 80 / 122 / 463 | ilk beşin beşi de değişti | 187.780 → 146.080 bayt |
| Eşlemeler ve Alan Tipleri | çocuk 93’e karşı 0 |
ilk onun onu oynadı | konu 8.203 → 11.686 bayt |
| Dinamik ve Açık Eşleme | çatışma 111 belge attı | düşen belge sırada görünmez | üstveri 1.595 → 3.022 bayt |
| Belge Yaşam Döngüsü | #10 kümeden kümeye geçti |
7. sıradan 509. sıraya | 119.722 → 136.322 bayt |
| Sorgu Dili Yapısı | 4.211 / 132 / 71 | 2.023. basamaktan ilk ona | 21.303 → 7.576 giriş |
| Terim ve İfade Sorguları | 757 → 144 | bitişik eşleşme 1 → 10 | 216.480 → 330.578 bayt |
| Bağlam Sorguları | olumsuz 512, isteğe bağlı 0 | ilk onun dokuzu değişti | giriş 2.678 → 4.638 |
| Süzme ve Sorgu Ayrımı | iki bağlamda da 1.138 | ortalama 173 basamak | puan hesabı 2.276 → 1.138 |
| İlgililik Puanlaması | kesinlik 0,353 → 0,640 | bileşen yokluğu 499 basamak | anma için 567 sonuç |
| Puan Ayarlama | ağırlık 325, alan seçimi 199 | ilk onun onu değişti | 698 → 265 giriş |
| Toplama Sorguları | 208 / 168 / 1 kova | sıra kova sırasıdır | 1.045 kova, 25.080 bayt |
| Vurgulama ve Sayfalama | 60 eşleşmeden 12’si dışarıda | sıra değişmez | 20. sayfa 800 aday |
| Anlamsal ve Vektör Arama | 0,5 eşiğinde 383 | ilk onun altısı eşanlamlıdan | 153.600 bayt |
| Düğüm Rolleri | geciken durum 800 kaydı reddetti | ilk beş tamamen değişti | eşgüdüm %0,8 → %11,4 |
| Parçalar ve Kopyalar | düğüm kaybında 515 → 379 | ilk on ortak 10,00 → 4,75 | aday 10 → 160 |
| Bölünmüş Beyin | azınlıkta 210 kayıt kayboldu | iki yarı iki liste verdi | 600 → 1590 ileti |
| Toplu Dizinleme | yenileme kapalıyken 600 eksik | ilk on 6/10 | 4000 bölüt, 24.000 arama |
| Bölüt Birleştirme | değişmedi, 18.775 | 50 basamağın 42’si farklı | 3.193.775 → 2.552.007 bayt |
| Dizin Yaşam Döngüsü | 10.262 → 12.274 | ilk onun ikisi silinmiş günden | giriş 19.476 → 1.993 |
| Anlık Görüntü ve Geri Yükleme | 7.879 → 17.387 | 49 basamak değişti | 10.790.530 → 3.180.562 bayt |
| Erişim Denetimi | okuyucu 2.463, görevli 4.743 | ilk on ortak 7/10 | giriş 2.998 → 7.175 |
Tablonun üç sütunu kursun kuralıdır: bir arama kararı ancak küme ve sıra üzerindeki etkisiyle savunulur. “Daha alakalı sonuç” bir karar değildir; bir çözümleyici, bir ağırlık, bir parça sayısı ya da bir yetki kuralı ancak hangi belgelerin hangi sırayla döndüğünü ve neye mal olduğunu söyleyerek savunulur.
Bu kurs M17’nin yedincisi ve sonuncusudur. İlişkisel Kuram verinin nasıl modelleneceğini, SQL Temelleri o modelin nasıl sorgulanacağını, İleri SQL aynı sorgunun neden yavaşladığını, Veritabanı Yönetimi çalışan bir dizgenin nasıl işletileceğini, İlişkisel Olmayan Veri Modelleri başka bir yolun neyi kazandırıp neyi bıraktığını, Bellek İçi Depolar bellek bütçesinin nasıl harcandığını kurdu. Bu kurs son boşluğu kapattı: anahtarı bilinmeyen veriye metnin içinden gitmeyi.
Buradan sonrası ölçüm alışkanlığıdır ve başlangıcı kendi verinin erişim örüntüsüdür: sorular anahtarla mı geliyor yoksa metnin içinden mi, kaç belge dönüyor, hangi sırayla ve o sırayı kim belirliyor. Yirmi üç dersin yaptığı tek şey buydu.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.