İçeriğe geç
academia.sh

Ders 09 / 23

Bağlam Sorguları

Zorunlu, olumsuz ve isteğe bağlı koşullar aynı bileşik sorguda ölçülür: olumsuz koşul kümeden 512 belge çıkarır, isteğe bağlı koşul bir belge bile çıkarmadan ilk on sonucun dokuzunu değiştirir, ama zorunlu koşul yokken aynı isteğe bağlı koşul kümeyi belirleyen koşula dönüşür.

İçindekiler

Önceki iki derste kurulan koşulların hepsi aynı türdendi: koşulu sağlamayan belge kümeden düşerdi. Katalog soruları bu kadar tek biçimli değildir. Bir okur şunu söyler: “Çocuk kitabı olsun, almanca olmasın, resimli olanlar üstte olsun.” Üç istek de tek bir cümlede geçer, ama üçü aynı işi yapmaz. Birincisi kümeyi belirler, ikincisi kümeden çıkarır, üçüncüsü kümeden hiç kimseyi çıkarmaz — yalnız listenin başını değiştirir.

Bileşik sorgu bu ayrımı koşul bağlamı ile yapar. Zorunlu koşul (must) sağlanmayan belgeyi eler. Olumsuz koşul (must not) sağlayan belgeyi eler. İsteğe bağlı koşul (should) hiçbir belgeyi elemez; sağlayan belgeye puan ekler. Bu ders üç bağlamın kümeye ve sıraya etkisini ayrı ayrı sayar ve isteğe bağlı koşulun bir yerde kural değiştirdiğini gösterir.

Derlem ve Puan Kuralı

Derlem önceki derslerin modülüdür: 6.000 kitap kaydı, tohum 271828, belirlenimli üretim. SI6 (varsayım): bu derste puan, karşılanan isteğe bağlı koşul sayısıdır; eşitlik belge numarasıyla bozulur. Terim sıklığına ve seyrekliğe dayanan gerçek puan modeli bu konunun beşinci dersinde kurulur — burada ölçülen şey puanın büyüklüğü değil, isteğe bağlı koşulun sıraya dokunup kümeye dokunmaması.

// derlem.mjs — kutuphane katalogu derlemi ve konum bilgili ters dizin.
// Tohum 271828, 6000 belge; konudaki butun olcumler bu modulu paylasir.
export const TOHUM = 271828, N = 6000;
let c = TOHUM;                                       // gorunur tohum, belirlenimli uretec
const r = () => { c = (c + 0x6d2b79f5) | 0; let t = Math.imul(c ^ (c >>> 15), 1 | c);
  t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; return ((t ^ (t >>> 14)) >>> 0) / 4294967296; };
const sec = (d, e = 1) => d[Math.floor(r() ** e * d.length)];   // e>1: bas ogeler sik, son ogeler seyrek

const SIFAT = ["eleştirel", "kısa", "resimli", "seçme", "karşılaştırmalı"];
const TUR = ["deneme", "öykü", "roman", "inceleme", "antoloji"];
const ALAN = ["çocuk", "tarih", "bilim", "felsefe", "toplum"];
const SON = ["seçkisi", "kitabı", "derlemesi", "dizisi"];
const NIT = ["kapsamlı", "özlü", "tanıtıcı", "tartışmalı"];
const KONU = ["eğitim", "göç", "kent", "bellek", "doğa", "müzik", "hukuk", "kimlik", "emek", "aile",
  "savaş", "gelenek", "sağlık", "yolculuk", "mimarlık", "arkeoloji", "denizcilik", "gökbilim"];
const YAZAR = ["Ahmet Yıldız", "Zeynep Kaya", "Kemal Demir", "Elif Şahin", "Necati Aydın"];
const DIL = ["türkçe", "ingilizce", "almanca"];

export const KATALOG = [];
for (let i = 1; i <= N; i += 1) {
  const s = sec(SIFAT, 1.5), t = sec(TUR, 1.5), a = sec(ALAN, 2), k = r();
  const desen = k < 0.18 ? `${s} ${t}` : k < 0.30 ? `${s} bir ${t}`
    : k < 0.40 ? `${s} ve kuramsal ${t}` : k < 0.50 ? `${t} ve ${s} inceleme`
    : k < 0.70 ? `${s} bir anlatı` : k < 0.88 ? `çağdaş bir ${t}` : "alan yazını taraması";
  KATALOG.push({ id: `K-${String(i).padStart(4, "0")}`, ad: `${a} ${t} ${sec(SON)}`,
    ozet: `${a} alanında ${desen}; ${sec(KONU, 3)} ve ${sec(KONU, 3)} üzerine ` +
      `${sec(NIT)} bir ${sec(TUR, 1.5)} olarak okunabilir.`,
    etiket: [a, t], yazar: sec(YAZAR), yil: 1990 + Math.floor(r() * 35), dil: sec(DIL, 2) });
}

export const belirtecle = (m) => m.toLocaleLowerCase("tr").split(/[^\p{L}\p{N}]+/u).filter(Boolean);

// Ters dizin: "alan|terim" -> Map(belge sirasi -> konumlar); uzunluk: alan basina belirtec sayisi.
export function tersDizin(alanlar) {
  const g = new Map(), uzunluk = new Map();
  KATALOG.forEach((b, i) => {
    for (const alan of alanlar) {
      const tk = belirtecle(String(b[alan]));
      uzunluk.set(`${alan}|${i}`, tk.length);
      tk.forEach((t, p) => {
        let l = g.get(`${alan}|${t}`); if (!l) g.set(`${alan}|${t}`, (l = new Map()));
        let k2 = l.get(i); if (!k2) l.set(i, (k2 = [])); k2.push(p);
      });
    }
  });
  return { g, uzunluk };
}

Üç Bağlamın Ölçümü

// baglam.mjs — zorunlu, olumsuz ve istege bagli kosullar. Ayni dizinde derlem.mjs bulunur.
// Istege bagli kosul kumeden belge elemez; yalniz puan uretir. Puan burada karsilanan
// istege bagli kosul sayisidir; esitlik belge numarasiyla bozulur.
import { KATALOG, TOHUM, tersDizin } from "./derlem.mjs";
const { g } = tersDizin(["ad", "ozet", "etiket", "dil"]);
const kume = (alan, terim) => new Set(g.get(`${alan}|${terim}`)?.keys() ?? []);

function calistir(sorgu, s) {
  let aday = null;
  for (const [alan, terim] of sorgu.zorunlu ?? []) {
    const k = kume(alan, terim); s.taranan += k.size;
    aday = aday === null ? [...k] : aday.filter((d) => k.has(d));
  }
  const istek = (sorgu.istege ?? []).map(([a, t]) => { const k = kume(a, t); s.taranan += k.size; return k; });
  if (aday === null) {                       // zorunlu kosul yoksa kumeyi istege bagli kosullar belirler
    const b = new Set();
    for (const k of istek) for (const d of k) b.add(d);
    aday = [...b];
  }
  for (const [alan, terim] of sorgu.olumsuz ?? []) {
    const k = kume(alan, terim); s.taranan += k.size;
    aday = aday.filter((d) => !k.has(d));
  }
  aday.sort((x, y) => x - y);
  const puan = new Map(aday.map((d) => [d, istek.filter((k) => k.has(d)).length]));
  const sirali = [...aday].sort((x, y) => puan.get(y) - puan.get(x) || x - y);
  return { kume: aday, puan, sirali };
}
const olc = (ad, sorgu) => {
  const s = { taranan: 0 }, c = calistir(sorgu, s);
  console.log(`${ad.padEnd(38)} ${String(c.kume.length).padStart(4)} belge   taranan giris ${String(s.taranan).padStart(5)}`);
  return c;
};

console.log(`derlem ${KATALOG.length} belge, tohum ${TOHUM}`);
const Z = [["etiket", "çocuk"]], I = [["ozet", "resimli"], ["ad", "öykü"]], O = [["dil", "almanca"]];
const a = olc("zorunlu[etiket:çocuk]", { zorunlu: Z });
const b = olc("zorunlu + olumsuz[dil:almanca]", { zorunlu: Z, olumsuz: O });
const c = olc("zorunlu + istege bagli[resimli, öykü]", { zorunlu: Z, istege: I });
const d = olc("zorunlu + istege bagli + olumsuz", { zorunlu: Z, istege: I, olumsuz: O });
const e = olc("yalniz istege bagli[resimli, öykü]", { istege: I });
console.log(`olumsuz kosulun cikardigi belge ${a.kume.length - b.kume.length}`);
console.log(`istege bagli kosulun kumeye etkisi ${c.kume.length - a.kume.length} belge`);

const ilkOn = (l) => l.slice(0, 10).map((x) => KATALOG[x].id);
const degisen = ilkOn(c.sirali).filter((x) => !ilkOn(a.sirali).includes(x)).length;
console.log(`ilk on: zorunlu ${ilkOn(a.sirali).join(" ")}`);
console.log(`ilk on: +istege ${ilkOn(c.sirali).join(" ")}   degisen ${degisen}/10`);
const ikiPuan = c.sirali.filter((x) => c.puan.get(x) === 2);
console.log(`iki istege bagli kosulu da karsilayan ${ikiPuan.length} belge; ` +
  `ilki ${KATALOG[ikiPuan[0]].id} zorunlu sirada ${a.kume.indexOf(ikiPuan[0]) + 1}. basamaktaydi`);
const oynama = ikiPuan.map((x) => a.kume.indexOf(x) + 1 - (c.sirali.indexOf(x) + 1));
console.log(`bu belgelerin basamak kazanci ortalama ${Math.round(oynama.reduce((x, y) => x + y, 0) / oynama.length)}, ` +
  `en buyugu ${Math.max(...oynama)}`);
derlem 6000 belge, tohum 271828
zorunlu[etiket:çocuk]                  2678 belge   taranan giris  2678
zorunlu + olumsuz[dil:almanca]         2166 belge   taranan giris  3800
zorunlu + istege bagli[resimli, öykü]  2678 belge   taranan giris  4638
zorunlu + istege bagli + olumsuz       2166 belge   taranan giris  5760
yalniz istege bagli[resimli, öykü]     1802 belge   taranan giris  1960
olumsuz kosulun cikardigi belge 512
istege bagli kosulun kumeye etkisi 0 belge
ilk on: zorunlu K-0004 K-0008 K-0016 K-0018 K-0020 K-0023 K-0024 K-0026 K-0033 K-0037
ilk on: +istege K-0037 K-0072 K-0078 K-0080 K-0216 K-0345 K-0371 K-0518 K-0615 K-0712   degisen 9/10
iki istege bagli kosulu da karsilayan 82 belge; ilki K-0037 zorunlu sirada 10. basamaktaydi
bu belgelerin basamak kazanci ortalama 1263, en buyugu 2574

Küme: İki Koşul Türü Eler, Biri Elemez

Zorunlu koşul tek başına 2.678 belge döndürür — çocuk etiketli kitaplar. Olumsuz koşul eklendiğinde küme 2.166’ya iner: 512 belge çıkar, hepsi almanca kayıtlardır. Olumsuz koşulun ürettiği sayı hep bir çıkarmadır; kümeye asla belge eklemez ve tek başına kullanıldığında anlamı belirsizdir, çünkü “almanca olmayan” ifadesi hangi kümeden çıkarılacağını söylemez.

Üçüncü satır dersin çekirdeğidir. Aynı zorunlu koşula iki isteğe bağlı koşul eklendi ve küme 2.678 belge olarak kaldı: giren yok, çıkan yok, fark sıfır. Resimli olmayan ve adında “öykü” geçmeyen bir kitap sonuç listesinden düşmedi; yalnız puanı sıfır kaldı. Dördüncü satır aynı sorguya olumsuz koşulu geri koyar ve küme yine 2.166’ya iner — çünkü kümeyi değiştiren şey isteğe bağlı koşul değil, olumsuz koşuldur.

Beşinci satır kuralın sınırını gösterir ve pratikte en çok yanlış anlaşılan noktadır. Zorunlu koşul kaldırıldığında, aynı iki isteğe bağlı koşul kümeyi 1.802 belgeye indirir. İsteğe bağlı koşul burada birden elemeye başlamış değildir; olan şey şudur: kümeyi belirleyen hiçbir koşul kalmayınca en az bir isteğe bağlı koşulun sağlanması gerekir, yoksa sorgu bütün derlemi döndürürdü. Yani “isteğe bağlı koşul kümeyi değiştirmez” cümlesi koşulsuz doğru değildir; doğrusu şudur: kümeyi belirleyen başka bir koşul varsa isteğe bağlı koşul kümeye dokunmaz. Bir arayüzde ağırlıklandırma amacıyla eklenen bir koşulun, zorunlu koşulun kaldırıldığı bir durumda sonucu 6.000’den 1.802’ye düşürmesi bu kuraldan gelir.

Sıra ve Bedel: Elemeyen Koşulun Ödettiği

Küme değişmediği hâlde liste tanınmaz hâle gelir. Zorunlu koşulun tek başına verdiği ilk on sonuç K-0004 ile başlar; isteğe bağlı koşullar eklendiğinde ilk onun dokuzu değişir. Ayakta kalan tek kayıt K-0037’dir ve o da onuncu basamaktan birinci basamağa çıkmıştır. İki isteğe bağlı koşulu birden karşılayan 82 belge vardır; bu belgeler ortalama 1.263 basamak yukarı çıkar, en çok yükselen 2.574 basamak kazanır. 2.678 belgelik bir listede 2.574 basamaklık bir sıçrama, belgenin listenin sonundan başına gelmesi demektir.

Bedel tarafı da elemeyen koşulun bedava olmadığını gösterir. Zorunlu koşul tek başına 2.678 giriş okur. İsteğe bağlı iki koşul eklendiğinde okuma 4.638 girişe çıkar: %73,2 artış, tek bir belge bile elenmeden. Bunun nedeni açıktır — isteğe bağlı koşulun puana katkısını hesaplamak için gönderi listesinin tamamı okunmalıdır, oysa zorunlu koşul aday kümesi küçüldükçe daha az iş yapar. Üç bağlamın hepsi bir aradayken okuma 5.760 girişe ulaşır; bunun 1.122’si yalnız 512 belgeyi çıkarmak için okunan olumsuz koşul listesidir.

Buradan çıkan işletim kuralı şudur: bir koşulun ucuz olup olmadığı, kaç belge elediğine değil, kaç giriş okuttuğuna bakarak söylenir. Kümeyi hiç değiştirmeyen bir koşul en pahalı koşul olabilir.

Özet

  • Zorunlu koşul kümeyi belirler, olumsuz koşul kümeden çıkarır, isteğe bağlı koşul yalnız puan üretir; 6.000 belgelik derlemde (tohum 271828) olumsuz koşul 512 belge çıkarır, isteğe bağlı koşul 0 belge çıkarır.
  • İsteğe bağlı koşulun kümeye etkisizliği koşulludur: kümeyi belirleyen başka bir koşul yoksa en az biri sağlanmalıdır ve küme 6.000 yerine 1.802 belge olur.
  • Küme sabitken sıra baştan yazılır: ilk on sonucun dokuzu değişir, iki isteğe bağlı koşulu karşılayan 82 belge ortalama 1.263 basamak yükselir, en çok yükselen 2.574 basamak kazanır.
  • Elemeyen koşul bedavaya çalışmaz: isteğe bağlı iki koşul taranan girişi 2.678’den 4.638’e çıkarır, hiçbir belgeyi elemeden.
  • Bir koşulun bedeli elediği belge sayısıyla değil, okuttuğu gönderi girişiyle ölçülür.

Sonraki Adım

Üç bağlam da bir noktada birleşiyor: hepsi puanlayıcının önünden geçiyor. Zorunlu koşul kümeyi belirlerken aynı zamanda puana katkı veriyor, isteğe bağlı koşul zaten yalnız bunun için var. Oysa katalog koşullarının bir bölümü puana hiç katılmamalıdır. “Yayın yılı 2010 ve sonrası” ya da “dili türkçe” gibi bir koşul ya sağlanır ya sağlanmaz; bir kitabın 2015 basımı olması onu 2011 basımı bir kitaptan daha ilgili yapmaz. Bu koşullar ayrı bir bağlamda değerlendirilir ve o bağlamın iki sonucu vardır: puan hesabı kısalır ve sonuç yeniden kullanılabilir hâle gelir, çünkü aynı koşul her sorguda aynı belgeleri verir. Sonraki ders aynı koşulu iki bağlamda çalıştırır, kümenin aynı kalıp sıranın değiştiğini gösterir ve önbelleklenen koşulun ikinci koşumda kaç giriş okuduğunu sayar.

İ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