---
title: 'Eşlemeler ve Alan Tipleri'
source: 'https://academia.sh/tr/kurslar/arama-motorlari/eslemeler-ve-alan-tipleri'
course: 'Arama Motorları ve Metin Erişimi'
language: tr
updated: '2026-08-17T18:09:01+00:00'
license: 'CC BY-SA 4.0'
---

# Eşlemeler ve Alan Tipleri

Alanın tipinin dizinleme kuralını belirlemesi: metin alanı ile anahtar sözcük alanının ayrımı, aynı alanın iki tiple dizinlenip terim sayısı, gönderi girişi ve dizin baytının karşılaştırılması, tam eşleme ile parça eşlemenin dönen kümeye etkisi, çok değerli alanda oluşan çapraz eşleşme, sıralama anahtarının tanımlı olup olmaması ve toplama kovalarının iki tipte ayrışması.

Önceki dersin üç zinciri de aynı kuralı bütün metne uyguladı. Katalogda ise her alan metin
değildir. Raf kodu `TR-866.3` bir yer belirtir ve bölünmesi anlamsızdır; dil `Türkçe` bir
değerdir; konu etiketi `çocuk edebiyatı` iki sözcükten oluşur ama tek bir kategoridir. Özet ise
gerçekten metindir ve içindeki her sözcük ayrı bir arama girişidir.

Bir alanın hangi kurala göre dizinleneceğini bildiren tanıma **eşleme** denir; eşlemenin taşıdığı
karara da **alan tipi**. Bu ders iki tipi karşılaştırıyor. **Metin alanı** değeri çözümleyici
zincirinden geçirir; sonuçta alan birden çok terime dağılır. **Anahtar sözcük alanı** değeri
bölmez, dönüştürmez: değerin tamamı tek bir terimdir.

## İki Tip, Aynı Alan

Ölçüm üç alan üzerinde yapılıyor: çok değerli `konu`, tek değerli `raf` ve tek değerli `dil`.
Her alan iki kez dizinleniyor ve dört şey sayılıyor: dizinin boyutu, tam değer sorgusunun
döndürdüğü küme, sıralamanın tanımlı olup olmadığı ve toplamanın ürettiği kova sayısı.

**DC1:** derlem aynıdır — 600 kayıt, tohum 20250317. **DC2:** bayt sabitleri önceki derslerdeki
sabitlerdir; bu derste konum tutulmuyor. **DC3:** çok değerli alanda anahtar sözcük tipi her
değeri ayrı bir terim yapar, metin tipi bütün değerleri tek bir metin gibi çözümler. **DC4:**
metin alanında belge başına birden çok terim olduğu için sıralama anahtarı seçilmek zorundadır;
burada "en küçük terim" kuralı seçilmiştir.

```js
// arama/katalog.mjs — uc konunun paylastigi derlem: kutuphane katalogundan uretilmis
// 600 kitap kaydi, tohum 20250317. Alanlar: ad, ozet, konu, yazar, yil, dil, raf.
export const TOHUM = 20250317, BELGE = 600;
let cekirdek = TOHUM;
const rast = () => (cekirdek = (cekirdek * 1103515245 + 12345) % 2147483648) / 2147483648;
const sec = (d) => d[Math.floor(rast() * d.length)];
const secZ = (d) => d[Math.floor(rast() ** 2 * d.length)];   // gercek metinde siklik carpiktir
const ayir = (s) => s.split("|");

// govde sozcugu: yalin, tamlayan, cogul, yonelme, ayrilma, bulunma
export const KOK = ayir("deniz denizin denizler denize denizden denizde|kitap kitabın kitaplar kitaba \
kitaptan kitapta|çocuk çocuğun çocuklar çocuğa çocuktan çocukta|şehir şehrin şehirler şehre \
şehirden şehirde|yol yolun yollar yola yoldan yolda|ada adanın adalar adaya adadan adada|bahçe \
bahçenin bahçeler bahçeye bahçeden bahçede|mektup mektubun mektuplar mektuba mektuptan mektupta|\
gemi geminin gemiler gemiye gemiden gemide|köprü köprünün köprüler köprüye köprüden köprüde|\
okul okulun okullar okula okuldan okulda|kuş kuşun kuşlar kuşa kuştan kuşta").map((s) => s.split(" "));
const KALIP = ayir("0 {} ve gündelik hayat üzerine notlar sunar|0 {} bu derlemenin ana izleğidir|\
1 {} tarihine geniş yer ayırır|1 {} çevresinde gelişen olayları anlatır|2 {} üzerine derlenmiş \
yazılar içerir|2 {} hakkında kısa öyküler toplar|3 {} açılan bir yolculuğu izler|4 {} toplanmış \
belgeleri sıralar|5 {} tutulan günlüklerden seçmeler verir|5 {} geçen bölümleri İstanbul'un eski \
mahallelerine bağlar").map((s) => [Number(s[0]), s.slice(2)]);
const KALIP2 = ayir("{Y} kütüphanesinde tutulan {N} üzerine kuruludur|{N} arasından seçilmiş \
örnekler taşır|{Y} ve çevresindeki {N} listesini verir|{Y} basımı bir {N} derlemesine dayanır");
const EK = ayir("denizci gelenekleri üzerine bir ek bölüm bulunur|Karadeniz kıyısındaki kasabaları \
anlatır|çocukluk anılarına yer verir|kitapçı raflarındaki dağılımı tartışır|yolculuk notlarıyla \
kapanır|adacıklardaki kuş türlerini sayar");
const YER = ayir("Ankara|İzmir|Trabzon|Kars|Bursa|Edirne|Sinop|Antakya");
const NESNE = ayir("harita|fotoğraf|söyleşi|günlük|arşiv belgesi|liman kaydı|kasaba adı|el yazması|gazete kupürü|şarkı sözü");
const ONEK = ayir("Uzak|Kayıp|Sessiz|Eski|Kısa|Büyük|Küçük|Unutulmuş|Beyaz|Yedi");
const SONEK = ayir("Günleri|Öyküleri|Üzerine Notlar|Anıları|Sözlüğü|Rehberi|Yılları|Defteri");
const KONU = ayir("çocuk edebiyatı|roman|kısa öykü|şiir|deniz tarihi|coğrafya|biyografi|gezi yazısı|halk bilimi|mimarlık|müzik|felsefe");
const AD = ayir("Ahmet|Ayşe|Zeynep|Cemal|Nuran|Selim|Elif|Kerem|Hatice|Bedri|Sevgi|Nazlı");
const SOYAD = ayir("Yılmaz|Kaya|Demir|Şahin|Çelik|Aydın|Doğan|Arslan|Koç|Ertem");
const DIL = ayir("Türkçe|Türkçe|Türkçe|İngilizce|Almanca|Fransızca");

const buyut = (s) => s[0].toLocaleUpperCase("tr") + s.slice(1);
function ozetUret() {
  const parca = [];
  for (let i = 0; i < 3; i += 1) { const [d, k] = secZ(KALIP); parca.push(k.replace("{}", secZ(KOK)[d])); }
  parca.push(sec(KALIP2).replace("{Y}", sec(YER)).replace("{N}", sec(NESNE)));
  if (rast() < 0.45) parca.push(sec(EK));
  return buyut(parca.join(", ")) + ".";
}
function adUret() {
  const k = secZ(KOK), o = sec(ONEK), s = sec(SONEK), t = rast();
  if (t < 0.25) return `${o} ${buyut(k[2])}`;
  if (t < 0.5) return `${buyut(k[0])} ${s}`;
  if (t < 0.75) return `${o} ${buyut(k[0])} ${s}`;
  return `${buyut(k[1])} ${s}`;
}
export const derlem = [];
for (let i = 1; i <= BELGE; i += 1) {
  const konu = [sec(KONU)];
  if (rast() < 0.55) konu.push(sec(KONU));
  if (rast() < 0.2) konu.push(sec(KONU));
  derlem.push({
    id: i, ad: adUret(), ozet: ozetUret(), konu: [...new Set(konu)], yazar: `${sec(AD)} ${sec(SOYAD)}`,
    yil: 1968 + Math.floor(rast() * 57), dil: sec(DIL),
    raf: `${sec(ayir("TR|EN|DE|FR"))}-${800 + Math.floor(rast() * 99)}.${Math.floor(rast() * 9)}`,
  });
}
```

```js
// arama/dizin.mjs — kendi yazilan ters dizin: sozluk, gonderi listesi (belge kimligi, terim
// sikligi, konum) ve bayt sayimi. Cozumleyici disaridan verilir; sonraki dersler bunu kullanir.
export const BASIT = (s) => s.toLocaleLowerCase("tr").split(/[^\p{L}\p{N}]+/u).filter(Boolean);
export const KIMLIK = 4, SIKLIK = 4, KONUM = 4, SOZLUK_EK = 8;   // DC2: bayt sabitleri

export class TersDizin {
  sozluk = new Map();                    // terim -> gonderi listesi
  belge = 0;
  constructor({ coz = BASIT, siklik = true, konum = true } = {}) { Object.assign(this, { coz, siklik, konum }); }

  ekle(id, metin) {
    const yerel = new Map();
    this.coz(metin).forEach((t, i) => (yerel.get(t) ?? yerel.set(t, []).get(t)).push(i));
    for (const [t, k] of yerel) {
      if (!this.sozluk.has(t)) this.sozluk.set(t, []);
      this.sozluk.get(t).push({ id, tf: k.length, konum: this.konum ? k : [] });
    }
    this.belge += 1;
  }

  liste(t) { return this.sozluk.get(t) ?? []; }

  ara(...terim) {                        // kesisim: listeler kimlik sirali oldugu icin tek gecis
    const l = terim.map((t) => this.liste(t)), p = l.map(() => 0), kume = [];
    let kars = 0;
    while (l.every((x, i) => p[i] < x.length)) {
      const en = Math.max(...l.map((x, i) => x[p[i]].id));
      let ayni = true;
      for (let i = 0; i < l.length; i += 1) {
        while (p[i] < l[i].length && l[i][p[i]].id < en) { p[i] += 1; kars += 1; }
        kars += 1;
        if (p[i] >= l[i].length || l[i][p[i]].id !== en) { ayni = false; break; }
      }
      if (ayni) { kume.push(en); p.forEach((_, i) => (p[i] += 1)); }
    }
    return { kume, giris: l.reduce((t, x) => t + x.length, 0), kars };
  }

  bayt() {                               // sozluk + gonderi + konum
    let s = 0, g = 0, k = 0, giris = 0, konum = 0;
    for (const [t, liste] of this.sozluk) {
      s += Buffer.byteLength(t) + SOZLUK_EK;
      for (const gr of liste) {
        g += KIMLIK + (this.siklik ? SIKLIK : 0);
        k += gr.konum.length * KONUM;
        giris += 1; konum += gr.konum.length;
      }
    }
    return { terim: this.sozluk.size, giris, konum, sozluk: s, gonderi: g, konumBayt: k, toplam: s + g + k };
  }
}
```

```js
// arama/alan-tipi.mjs — ayni alanlar iki tiple dizinlenir: metin alani (cozumleyiciden gecer)
// ve anahtar sozcuk alani (deger tek terim kalir). Bayt, tam esleme, siralama ve toplama.
import { derlem, BELGE, TOHUM } from "./katalog.mjs";
import { TersDizin } from "./dizin.mjs";

const AYRAC = "\u0001";                                     // deger siniri
const deger = { konu: (b) => b.konu, raf: (b) => [b.raf], dil: (b) => [b.dil] };
const METIN = (s) => s.toLocaleLowerCase("tr").split(/[^\p{L}\p{N}]+/u).filter(Boolean);
const ANAHTAR = (s) => s.split(AYRAC).filter(Boolean);       // deger bolunmez
const kur = (alan, coz) => {
  const d = new TersDizin({ coz, konum: false });
  for (const b of derlem) d.ekle(b.id, deger[alan](b).join(AYRAC));
  return d;
};
const dizin = new Map();
for (const alan of Object.keys(deger))
  for (const [tip, coz] of [["metin", METIN], ["anahtar sozcuk", ANAHTAR]])
    dizin.set(`${alan}/${tip}`, kur(alan, coz));

console.log(`tohum ${TOHUM}; derlem ${BELGE} belge; alanlar: konu (cok degerli), raf, dil`);
console.log(`\n${"alan".padEnd(6)}${"tip".padEnd(16)}${"terim".padStart(7)}${"gonderi".padStart(9)}` +
  `${"dizin bayt".padStart(12)}${"ornek terim".padStart(28)}`);
for (const [ad, d] of dizin) {
  const [alan, tip] = ad.split("/"), b = d.bayt();
  console.log(alan.padEnd(6) + tip.padEnd(16) + String(b.terim).padStart(7) + String(b.giris).padStart(9) +
    String(b.toplam).padStart(12) + [...d.sozluk.keys()].slice(0, 2).join(" | ").padStart(28));
}

const sikRaf = [...derlem.reduce((m, b) => m.set(b.raf, (m.get(b.raf) ?? 0) + 1), new Map())]
  .sort((x, y) => y[1] - x[1])[0][0];                        // derlemde en cok yinelenen raf kodu
const soru = [["konu", "çocuk edebiyatı", "tam etiket"], ["konu", "çocuk", "etiketin tek sozcugu"],
  ["konu", "çocuk tarihi", "olmayan etiket"], ["raf", sikRaf, "tam raf kodu"], ["raf", "TR", "raf oneki"],
  ["dil", "Türkçe", "deger yazildigi gibi"], ["dil", "türkçe", "deger kucuk harfle"]];
console.log(`\n${"alan".padEnd(6)}${"sorgu".padEnd(18)}${"aciklama".padEnd(24)}${"metin".padStart(8)}${"anahtar sozcuk".padStart(16)}`);
for (const [alan, s, not] of soru) {
  const m = dizin.get(`${alan}/metin`).ara(...METIN(s)).kume.length;
  const a = dizin.get(`${alan}/anahtar sozcuk`).ara(s).kume.length;
  console.log(alan.padEnd(6) + s.padEnd(18) + not.padEnd(24) + String(m).padStart(8) + String(a).padStart(16));
}

// --- siralama: anahtar sozcuk alaninda belge basina tek terim, metin alaninda birden cok ---
const terimler = (d, id) => [...d.sozluk].filter(([, l]) => l.some((g) => g.id === id)).map(([t]) => t);
const mRaf = dizin.get("raf/metin"), aRaf = dizin.get("raf/anahtar sozcuk");
const cok = derlem.filter((b) => terimler(mRaf, b.id).length > 1).length;
const enKucuk = (d, id) => terimler(d, id).sort()[0];
const sirala = (d) => derlem.map((b) => [enKucuk(d, b.id), b.id]).sort((x, y) => (x[0] < y[0] ? -1 : x[0] > y[0] ? 1 : x[1] - y[1]));
const aSira = sirala(aRaf), mSira = sirala(mRaf);
const farkli = aSira.slice(0, 10).filter(([, id], i) => mSira[i][1] !== id).length;
console.log(`\nsiralama (raf alanina gore): metin tipinde ${cok} belgenin alaninda birden cok terim var; ` +
  `${new Set(mSira.map(([t]) => t)).size} ayri siralama anahtari`);
console.log(`anahtar sozcuk tipinde ${new Set(aSira.map(([t]) => t)).size} ayri anahtar; ` +
  `ilk on belgenin ${farkli} tanesi iki siralamada farkli`);
console.log(`  anahtar sozcuk ilk uc: ${aSira.slice(0, 3).map(([t, i]) => `${t} (#${i})`).join(", ")}`);
console.log(`  metin ilk uc        : ${mSira.slice(0, 3).map(([t, i]) => `${t} (#${i})`).join(", ")}`);

// --- toplama: konu alaninda kova sayimi ---
const kova = (d) => [...d.sozluk].map(([t, l]) => [t, l.length]).sort((x, y) => y[1] - x[1] || (x[0] < y[0] ? -1 : 1));
for (const tip of ["anahtar sozcuk", "metin"]) {
  const k = kova(dizin.get(`konu/${tip}`));
  console.log(`\nkonu toplamasi (${tip}): ${k.length} kova, toplam ${k.reduce((t, [, n]) => t + n, 0)} belge sayimi`);
  console.log(`  en buyuk uc: ${k.slice(0, 3).map(([t, n]) => `${t} ${n}`).join(", ")}`);
}
```

```
tohum 20250317; derlem 600 belge; alanlar: konu (cok degerli), raf, dil

alan  tip               terim  gonderi  dizin bayt                 ornek terim
konu  metin                17     1430       11686            biyografi | kısa
konu  anahtar sozcuk       12      999        8203       biyografi | kısa öykü
raf   metin               112     1800       15610                    en | 893
raf   anahtar sozcuk      549      600       13584         EN-893.5 | FR-881.4
dil   metin                 4      600        4866         almanca | fransızca
dil   anahtar sozcuk        4      600        4867         Almanca | Fransızca

alan  sorgu             aciklama                   metin  anahtar sozcuk
konu  çocuk edebiyatı   tam etiket                    93              93
konu  çocuk             etiketin tek sozcugu          93               0
konu  çocuk tarihi      olmayan etiket                 9               0
raf   TR-866.3          tam raf kodu                   3               3
raf   TR                raf oneki                    154               0
dil   Türkçe            deger yazildigi gibi         310             310
dil   türkçe            deger kucuk harfle           310               0

siralama (raf alanina gore): metin tipinde 600 belgenin alaninda birden cok terim var; 9 ayri siralama anahtari
anahtar sozcuk tipinde 549 ayri anahtar; ilk on belgenin 10 tanesi iki siralamada farkli
  anahtar sozcuk ilk uc: DE-801.1 (#460), DE-801.8 (#94), DE-802.5 (#594)
  metin ilk uc        : 0 (#19), 0 (#31), 0 (#42)

konu toplamasi (anahtar sozcuk): 12 kova, toplam 999 belge sayimi
  en buyuk uc: coğrafya 95, çocuk edebiyatı 93, biyografi 88

konu toplamasi (metin): 17 kova, toplam 1430 belge sayimi
  en buyuk uc: coğrafya 95, edebiyatı 93, çocuk 93
```

## Bayt Farkı Alanın Kendisine Bağlıdır

İlk tablo tek bir kural vermiyor, çünkü iki tipin hangisinin ucuz olduğu alana göre değişiyor.
`konu` alanında metin tipi hem daha çok terim (17'ye 12) hem daha çok gönderi girişi (1.430'a 999)
üretiyor ve 11.686 baytla anahtar sözcük tipinin 8.203 baytının üstüne çıkıyor: iki sözcüklü
etiketler bölününce her belge alanda iki giriş bırakıyor.

`raf` alanında yön tersine dönüyor. Metin tipi sözlüğü küçültüyor — 549 ayrı kod yerine 112 parça,
çünkü aynı sayı ve önek yüzlerce kodda tekrar ediyor — ama gönderi girişini üçe katlıyor: 600
yerine 1.800. Toplamda yine metin tipi pahalı (15.610'a 13.584), fakat pahalılık bu kez gönderi
tarafından geliyor. `dil` alanı iki tipin ancak bir bayt ayrıldığı sınır durumdur: değer zaten tek
sözcük olduğu için tip kararı boyutu değiştirmiyor, yalnız yazımı koruyor.

## Tam Eşleme, Sıralama ve Toplama

İkinci tablo kararın kümeye etkisini gösteriyor. Tam etiket sorulduğunda iki tip aynı 93 belgeyi
döndürüyor; ayrım öbür satırlarda. Etiketin **tek sözcüğü** sorulduğunda metin alanı 93 belge,
anahtar sözcük alanı 0 belge veriyor: metin alanı parça eşleşmeye açıktır, anahtar sözcük alanı
değilse değildir. Aynı davranış raf alanında `TR` önekiyle 154 belgeye karşı 0 belge biçiminde
tekrarlanıyor.

Üçüncü satır asıl uyarıdır. `çocuk tarihi` diye bir etiket derlemde **yoktur**; buna karşın metin
alanı 9 belge döndürüyor. Bunlar `çocuk edebiyatı` ve `deniz tarihi` etiketlerini birlikte taşıyan
belgelerdir: alan çok değerli olduğu için iki ayrı değerden gelen sözcükler tek bir eşleşme gibi
davranır. Anahtar sözcük alanı bu belgeleri getirmez, çünkü onun için her etiket bölünmemiş bir
bütündür. Ters yöndeki bedel dil satırında görünüyor: `türkçe` yazımıyla sorulduğunda anahtar
sözcük alanı 0 belge döndürür, çünkü değerde büyük harf vardır.

Sıralama farkı daha keskindir. Anahtar sözcük alanında her belgenin tek bir terimi vardır ve raf
kodu 549 ayrı sıralama anahtarı üretir; sıralama tanımlıdır. Metin alanında **600 belgenin
tamamının** alanında birden çok terim vardır, dolayısıyla "hangi terime göre" sorusu yanıtsızdır.
Seçilen kural en küçük terimi alınca elde 9 anahtar kalıyor ve ilk on belgenin onu da yer
değiştiriyor: sıralama pratikte anlamsızlaşıyor.

Toplama tarafında da iki tip aynı veriden iki tablo çıkarıyor. Anahtar sözcük alanı 12 kova ve
999 belge sayımı verir — bu, derlemdeki etiket sayısının tamıdır. Metin alanı 17 kova ve 1.430
sayım verir; `çocuk edebiyatı` etiketi `çocuk` ve `edebiyatı` diye iki kovaya bölünmüş, her ikisi
de 93 sayarak listenin başına yerleşmiştir. Kategori dağılımını görmek isteyen bir raporda bu iki
tablo aynı soruya farklı yanıt verir.

## Özet

- Eşleme alanın hangi kurala göre dizinleneceğini bildirir; metin alanı değeri çözümleyiciden
  geçirip terimlere böler, anahtar sözcük alanı değeri bölünmemiş tek terim olarak tutar.
- Boyut farkının yönü alana bağlıdır: `konu` alanında metin tipi 11.686 bayta karşı 8.203 bayt
  ile pahalıdır, `raf` alanında sözlüğü 549 terimden 112 terime indirir ama gönderi girişini
  600'den 1.800'e çıkarır.
- Tam eşleme yalnız anahtar sözcük alanında tam eşlemedir: `çocuk` sorgusu metin alanında 93,
  anahtar sözcük alanında 0 belge döndürür; `TR` öneki 154'e karşı 0 belge verir.
- Çok değerli alanda metin tipi çapraz eşleşme üretir: derlemde bulunmayan `çocuk tarihi` etiketi
  9 belge döndürür, çünkü sözcükler iki ayrı etiketten gelir.
- Sıralama metin alanında tanımsızdır: 600 belgenin tamamı birden çok terim taşır, seçilen kural
  9 anahtar bırakır ve ilk on belgenin onu da yer değiştirir. Toplama 12 kova yerine 17 kova
  üretir ve `çocuk edebiyatı` iki ayrı kovaya bölünür.

## Sonraki Adım

Bu dersteki eşleme elle yazıldı: hangi alanın hangi tiple dizinleneceği önceden bilinmişti. Gerçek
katalog aktarımında bu bilgi çoğu zaman yoktur — kayıtlar dışarıdan gelir, her kaynak kendi
alanlarını taşır ve tip kararını dizin kendisi verir. Sonraki ders bu kararı ölçüyor: belge
çeşitliliği arttıkça alan sayısının nasıl büyüdüğü, aynı adın iki farklı tiple gelmesi durumunda
ne olduğu ve her alanın dizin üstverisinde kaç bayta mal olduğu.
