Ders 09 / 19
Sorgu İşleçleri
Karşılaştırma, mantıksal ve dizi işleçlerinin semantiği kendi değerlendiricisinde kurulur: bir alan yolunun dizinin içine inmesi, koşulların belge düzeyinde mi öge düzeyinde mi karşılandığı, olumsuzlamanın dizide ve eksik alanda ne yaptığı, her biri dönen belge sayısıyla ölçülür.
İçindekiler
Önceki ders şemayı kurdu ve gömme kararının bedelini saydı; şube sorgusu ise elle yazılmış bir koşul işleviyle çalıştırıldı. Depo bu işi kendisi yapar ve bir işleç kümesiyle yapar: karşılaştırma işleçleri, mantıksal bağlaçlar ve dizilere özgü işleçler. Bu ders o kümenin söz dizimini ezberletmez — söz dizimi depodan depoya değişir ve zaten değişir. Değişmeyen şey semantiktir ve semantik burada kendi değerlendiricisinde kurulup ölçülür.
Ölçülecek asıl soru önceki dersin sonunda ortaya çıktı. Gömülü kopya dizisine iki koşul birden sorulduğunda koşulların aynı kopyada mı, yoksa belgenin herhangi iki kopyasında mı karşılanması gerektiği belirsizdir. İki okuma da tutarlıdır, ikisi de gerçekten kullanılır ve ikisi farklı sayıda belge döndürür.
Yolun Dizinin İçine İnmesi
İlişkisel bir koşul tek bir hücreye bakar. Belge modelinde bir alan yolu birden çok değere
ulaşabilir: kopya.sube yolu, üç kopyası olan bir kitapta üç değer üretir. Değerlendirici
bu durumda varoluşsal davranır — koşul, ulaşılan değerlerden herhangi biri
sağladığında doğar. Bu tek kural, dersin bütün ölçümlerinin kaynağıdır.
Değerlendirici üç işleç sınıfı taşır. Karşılaştırma işleçleri (=, <>, >, >=, <,
<=, icinde) bir değeri bir sabitle kıyaslar. Mantıksal bağlaçlar (ve, veya,
degil) koşulları birleştirir. Dizi işleçleri (ogede, tumu, hicbiri) ise ötekilerden
ayrılır: değerlere değil, ögelere bakar ve alt koşulu her ögeye ayrı ayrı uygular.
// islecler.mjs — kosul degerlendirici. Yol dizilerin icine iner: bir alan yolu birden // cok degere ulasabilir ve kosul o degerlerden herhangi biri saglarsa dogar. const KIYAS = { "=": (a, b) => a === b, "<>": (a, b) => a !== b, ">": (a, b) => a > b, ">=": (a, b) => a >= b, "<": (a, b) => a < b, "<=": (a, b) => a <= b, icinde: (a, b) => b.includes(a), }; // Yoldaki degerler. Dizi hem kendisi hem ogeleri olarak aday olur. export function degerler(kok, yol) { let kume = [kok]; for (const ad of yol.split(".")) { const sonraki = []; for (const d of kume) for (const o of Array.isArray(d) ? d : [d]) if (o && typeof o === "object" && !Array.isArray(o) && ad in o) sonraki.push(o[ad]); kume = sonraki; } return kume.flatMap((v) => (Array.isArray(v) ? [v, ...v] : [v])); } // Yoldaki dizilerin kendisi: oge duzeyi islecleri bunun uzerinde calisir. const diziler = (kok, yol) => degerler(kok, yol).filter(Array.isArray); export function eslesir(belge, kosul, s = { kiyas: 0, oge: 0 }) { for (const [ad, beklenen] of Object.entries(kosul)) { if (ad === "ve") { if (beklenen.every((k) => eslesir(belge, k, s))) continue; return false; } if (ad === "veya") { if (beklenen.some((k) => eslesir(belge, k, s))) continue; return false; } if (ad === "degil") { if (eslesir(belge, beklenen, s)) return false; continue; } const sade = beklenen === null || typeof beklenen !== "object" || Array.isArray(beklenen); const kosullar = sade ? { "=": beklenen } : beklenen; for (const [islec, operand] of Object.entries(kosullar)) { if (islec === "var") { if (degerler(belge, ad).length > 0 !== operand) return false; continue; } if (islec === "ogede" || islec === "tumu" || islec === "hicbiri") { const oge = diziler(belge, ad).flat(); s.oge += oge.length; const say = oge.filter((o) => eslesir(o, operand, s)).length; const dogru = islec === "ogede" ? say > 0 : islec === "tumu" ? say === oge.length && oge.length > 0 : say === 0; if (dogru) continue; return false; } const aday = degerler(belge, ad); s.kiyas += aday.length; if (aday.some((d) => KIYAS[islec](d, operand))) continue; return false; } } return true; } export const suz = (kume, kosul, s) => kume.filter((b) => eslesir(b, kosul, s));
Aynı Soru, İki Semantik
NS7 (varsayım): katalog 20.000 kitap belgesidir, her kitabın 1–5 kopyası ve 2–4 etiketi
vardır, tohum 424242’dir. NS12 (varsayım): esnek şemanın sonucu olarak belgelerin
kırkta birinde yayin_yili alanı hiç yoktur. Sorular önce belge düzeyinde, sonra öge
düzeyinde sorulur; her koşumda dönen belge sayısı, yapılan karşılaştırma sayısı ve
incelenen öge sayısı yazılır.
// islec-olcum.mjs — ayni uc soru iki islec bicimiyle sorulur: belge duzeyinde baglac ve // oge duzeyinde eslestirme. Donen belge sayisi ile yapilan karsilastirma sayilir. // Ayni dizinde islecler.mjs bulunur. import { suz } from "./islecler.mjs"; let cekirdek = 424242; // gorunur tohum const rast = () => (cekirdek = (cekirdek * 1103515245 + 12345) % 2147483648) / 2147483648; const SUBE = ["Merkez", "Bahcelievler", "Kadikoy", "Beyoglu", "Konak", "Nilufer"]; const DURUM = ["rafta", "oduncte", "onarimda"]; const ETIKETLER = ["roman", "tarih", "cocuk", "siir", "bilim", "basvuru"]; const KATALOG = []; for (let i = 1; i <= 20000; i += 1) { const kopya = [], etiket = []; for (let j = 0, n = 1 + Math.floor(rast() * 5); j < n; j += 1) kopya.push({ barkod: `B${String(i * 10 + j).padStart(7, "0")}`, sube: SUBE[Math.floor(rast() * 6)], durum: DURUM[Math.floor(rast() * 3)] }); for (let j = 0, n = 2 + Math.floor(rast() * 3); j < n; j += 1) etiket.push(ETIKETLER[Math.floor(rast() * 6)]); const b = { _k: `K-${String(i).padStart(5, "0")}`, yazar: `Yazar ${i % 4000}`, yayin_yili: 1950 + (i % 75), etiket, kopya }; if (i % 40 === 0) delete b.yayin_yili; // esnek sema: alan eksik olabilir KATALOG.push(b); } function calistir(ad, kosul) { const s = { kiyas: 0, oge: 0 }; const sonuc = suz(KATALOG, kosul, s); console.log(`${ad.padEnd(34)} ${String(sonuc.length).padStart(5)} belge ` + `karsilastirma ${String(s.kiyas).padStart(6)} incelenen oge ${String(s.oge).padStart(6)}`); return sonuc.length; } console.log(`katalog ${KATALOG.length} belge`); const a1 = calistir("belge duzeyi baglac", { "kopya.sube": "Kadikoy", "kopya.durum": "onarimda" }); const a2 = calistir("oge duzeyi eslestirme", { kopya: { ogede: { sube: "Kadikoy", durum: "onarimda" } } }); console.log(` aradaki ${a1 - a2} belgede kosullar ayri kopyalarda saglaniyor`); const b1 = calistir("kopya.durum <> oduncte", { "kopya.durum": { "<>": "oduncte" } }); const b2 = calistir("hicbir kopya oduncte degil", { kopya: { hicbiri: { durum: "oduncte" } } }); console.log(` aradaki ${b1 - b2} belgede en az bir kopya odunctedir`); const c1 = calistir("etiket icinde [tarih, bilim]", { etiket: { icinde: ["tarih", "bilim"] } }); const c2 = calistir("hem tarih hem bilim", { ve: [{ etiket: "tarih" }, { etiket: "bilim" }] }); const c3 = calistir("butun kopyalar rafta", { kopya: { tumu: { durum: "rafta" } } }); console.log(` icinde ile iki kosullu baglac arasindaki fark ${c1 - c2} belge`); calistir("yayin_yili alani yok", { yayin_yili: { var: false } }); calistir("yayin_yili >= 2010", { yayin_yili: { ">=": 2010 } }); calistir("yayin_yili < 2010 degil", { degil: { yayin_yili: { "<": 2010 } } });
katalog 20000 belge belge duzeyi baglac 6033 belge karsilastirma 88749 incelenen oge 0 oge duzeyi eslestirme 3340 belge karsilastirma 70018 incelenen oge 59494 aradaki 2693 belgede kosullar ayri kopyalarda saglaniyor kopya.durum <> oduncte 17787 belge karsilastirma 59494 incelenen oge 0 hicbir kopya oduncte degil 7111 belge karsilastirma 59494 incelenen oge 59494 aradaki 10676 belgede en az bir kopya odunctedir etiket icinde [tarih, bilim] 14033 belge karsilastirma 79730 incelenen oge 0 hem tarih hem bilim 2777 belge karsilastirma 115287 incelenen oge 0 butun kopyalar rafta 1919 belge karsilastirma 59494 incelenen oge 59494 icinde ile iki kosullu baglac arasindaki fark 11256 belge yayin_yili alani yok 500 belge karsilastirma 0 incelenen oge 0 yayin_yili >= 2010 3891 belge karsilastirma 19500 incelenen oge 0 yayin_yili < 2010 degil 4391 belge karsilastirma 19500 incelenen oge 0
Sayıların Söylediği
İlk çift dersin asıl bulgusudur. “Kadıköy şubesinde onarımda kopyası olan kitap” sorusu belge düzeyinde sorulduğunda 6.033 belge döner, öge düzeyinde sorulduğunda 3.340. Aradaki 2.693 belgede Kadıköy’de bir kopya vardır ve onarımda bir kopya vardır, ama bunlar farklı kopyalardır — Kadıköy’deki raftadır, onarımdaki başka şubededir. Belge düzeyi bağlaç yanlış değildir; sorusu farklıdır. Yanlış olan, öge düzeyinde bir soruyu belge düzeyinde sormaktır ve sonuç %80,6 fazla belgedir. Ölçüm bu farkı sessizce üretir: iki sorgu da çalışır, ikisi de hata vermez.
İkinci çift olumsuzlamanın dizideki davranışını gösterir. kopya.durum <> "oduncte" koşulu
17.787 belge döndürür; buradaki niyet neredeyse her zaman “hiçbir kopyası ödünçte olmayan
kitap”tır ve o soruya doğru yanıt 7.111’dir. Fark 10.676 belgedir — bu kitapların en az
bir kopyası ödünçtedir, ama en az bir kopyası da ödünçte değildir ve varoluşsal kural
koşulu doğurur. Olumsuzlama dizide, sezginin tersine, kapsayıcı çalışır: “değildir” ifadesi
“hiçbiri değildir” anlamına gelmez. Doğru ifade hicbiri işlecidir ve bu, öge düzeyinde
çalıştığı için 59.494 ögenin tamamını inceler.
Üçüncü çift, aynı yanlışın ters yönünü gösterir. icinde işleci diziye uygulandığında
“listedeki değerlerden herhangi biri” demektir ve 14.033 belge döndürür; “hem tarih hem
bilim etiketli kitap” sorusu ise iki koşullu bir bağlaçtır ve 2.777 belge döndürür. Fark
11.256’dır. Burada belge düzeyi bağlaç doğru araçtır, çünkü etiketler ayrı ögelerdedir
ve koşulların aynı ögede karşılanması istenmez. İki ölçüm birlikte kuralı verir: bağlacın
belge düzeyinde mi öge düzeyinde mi kurulacağını sorunun kendisi belirler, dizinin varlığı
değil.
tumu işleci 1.919 belge döndürür: bütün kopyaları rafta olan kitaplar. Bu işlecin
değerlendiricideki tanımı bir ayrıntı taşır — say === oge.length && oge.length > 0.
İkinci koşul olmasaydı, hiç kopyası olmayan bir kitap “bütün kopyaları rafta” sorusuna
doğru yanıt verirdi, çünkü boş bir küme üzerinde her önerme doğrudur. Boş dizinin bu
davranışı, belge modelinde alanın hiç bulunmamasıyla birlikte iki ayrı boşluk yaratır ve
ikisi de sorgunun yanıtını sessizce değiştirir.
Son üç satır esnek şemanın sorgu tarafındaki izidir. 500 belgede yayin_yili alanı yoktur.
yayin_yili >= 2010 bu belgeleri döndürmez (3.891), ama degil ile sarılmış aynı koşul
döndürür (4.391): eksik alan üzerinde hiçbir karşılaştırma doğmaz, dolayısıyla
olumsuzlaması doğar. Fark tam olarak 500’dür — alanı olmayan belge sayısı. Bir raporun
“2010 öncesi olmayan kitaplar” satırı, alanı hiç bulunmayan 500 kitabı da içine alır.
Karşılaştırma sayıları maliyeti verir. Öge düzeyi eşleştirme 70.018 karşılaştırma ve 59.494 öge incelemesi yapar, belge düzeyi bağlaç 88.749 karşılaştırma yapar. İkisi de derlemin tamamını okur: 20.000 belge. Bu, işleç seçiminin okunan belge sayısını değiştirmediği anlamına gelir — o sayıyı değiştiren şey dizindir ve bu konunun beşinci dersinin konusudur.
Özet
- Bir alan yolu dizinin içine iner ve birden çok değere ulaşır; koşul, ulaşılan değerlerden herhangi biri sağladığında doğar.
- “Kadıköy’de onarımdaki kopya” sorusu belge düzeyinde 6.033, öge düzeyinde 3.340 belge döndürür; 2.693 belgede iki koşul ayrı kopyalarda karşılanır.
- Dizide olumsuzlama kapsayıcıdır:
kopya.durum <> "oduncte"17.787 belge döndürür, “hiçbir kopyası ödünçte değil” 7.111 belge; fark 10.676’dır. icindeişleci diziye uygulandığında “herhangi biri” demektir (14.033 belge); “hepsi” sorusu iki koşullu belge düzeyi bağlaçla kurulur (2.777 belge).- Eksik alan hiçbir karşılaştırmayı doğurmaz, bu yüzden olumsuzlaması doğar:
yayin_yilialanı olmayan 500 belge, koşulun olumsuzlanmış biçimine düşer.
Sonraki Adım
İşleçler bir soruyu süzmeye yetiyor, ama kütüphanenin sorularının çoğu süzmeyle bitmez: “hangi şubede kaç kopya onarımda”, “en çok ödünç alınan beş kitap”, “yazar başına ortalama kopya sayısı”. Bunların hepsi süzmenin ardından gruplama, sayma ve sıralama ister ve bunları tek bir koşul ifadesiyle söylemek mümkün değildir. Belge modeli bu işi aşamalardan oluşan bir boru hattıyla yapar: her aşama bir kayıt akışı alır, dönüştürür ve bir sonrakine verir. Aşamaların sırası akışın uzunluğunu belirler — süzme başta mı sonda mı olduğuna göre sonraki aşamaların işlediği kayıt sayısı değişir. Sonraki ders o boru hattını kurar ve sıra kararının işlenen kayıt sayısına etkisini sayar.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.