---
title: 'Arama Motoru ve Veritabanı Farkı'
source: 'https://academia.sh/tr/kurslar/arama-motorlari/arama-motoru-ve-veritabani-farki'
course: 'Arama Motorları ve Metin Erişimi'
language: tr
updated: '2026-08-17T18:09:01+00:00'
license: 'CC BY-SA 4.0'
---

# Arama Motoru ve Veritabanı Farkı

Metnin içinden belgeye gitmenin ayrı bir yapı istemesi: anahtarı bilinen erişimle sözcüğü bilinen erişimin ayrımı, aynı katalog sorusunun ilişkisel LIKE taramasıyla ve terimden belgeye eşleyen ters dizinle yanıtlanması, iki yolun taradığı kayıt ile giriş sayısının, döndürdüğü belge kümesinin ve kaçırdığı belgelerin sayılması, büyük küçük harf ile çekim ekinin küme üzerindeki etkisi.

Bellek İçi Depolar kursu, ele aldığı bütün erişimlerin ortak bir varsayımıyla kapandı: aranan
şeyin **anahtarı biliniyordu**. Bir oturum kimliği, bir sayaç adı, bir sıralı kümenin adı verildi;
depo o adı bulup değeri getirdi. İlişkisel tarafta da durum benzerdi — dizin bir anahtar üzerinde
kuruldu, sorgu o anahtara eşitlik, aralık ya da önek koşuluyla gitti.

Kütüphane katalogunda sorular bu biçimde gelmiyor. Okur kitabın kimliğini değil, özetinde geçen
iki sözcüğü hatırlıyor: "özetinde deniz ve çocuk geçen kitaplar". Bu soru bir anahtara değil,
metnin **içine** gidiyor. Bu kurs o soruyu kuruyor ve her dersinde aynı iki şeyi sayıyor: bir
karar **hangi belgelerin döndüğünü** nasıl değiştirdi, **hangi sırayla** döndüklerini nasıl
değiştirdi ve bunun **bedeli** nedir. "Daha alakalı sonuç" bu kursta bir karar sayılmaz.

## Anahtardan Değil, Sözcükten Gitmek

İlişkisel dizin bir değerin **tamamı** üzerinde sıralanmış bir yapıdır. Eşitlik, aralık ve önek
sorularını bu sıralamayla yanıtlar; aranan parça değerin başında olmadığında sıralamanın söyleyeceği
bir şey kalmaz. `LIKE '%deniz%'` tam olarak bu durumdur: eşleşme metnin herhangi bir yerinde
olabileceği için dizin atlanır ve her kayıt okunur. Dizin kuramı M17/K04'te kurulmuştu; burada
önemli olan tek nokta, o dizinin bu soruya yardım edememesidir.

Ters dizin bunun tersini yapar. Belgeden alanlarına değil, **terimden belgelere** gider: metin
sözcüklere ayrılır, her sözcük için o sözcüğün geçtiği belgelerin kimlikleri saklanır. Soru
geldiğinde tablo değil, iki terimin listesi okunur. Yapının adı ve bayt hesabı sonraki derste
kuruluyor; bu ders yalnız iki yolun **aynı soruya verdiği yanıtı** karşılaştırıyor.

## Aynı Soru İki Yolda

Ölçüm için kütüphane katalogundan üretilmiş bir derlem kullanılıyor ve bu derlem kursun üç
konusunda da aynı kalıyor. **DC1:** derlem 600 kitap kaydı taşır, tohum 20250317'dir; her kayıtta
ad, özet, konu etiketleri, yazar, yıl, dil ve raf kodu bulunur; özet ortalama 25 sözcüktür ve
sözcük havuzu sınırlıdır — bu, terim sayısını gerçek bir katalogtan küçük tutar, oranları
değiştirmez. **DC2:** ilişkisel yolda taranan kayıt sayısı tablonun satır sayısıdır; sorgu planının
`SCAN` satırı bunu doğrular, okunan bayt özet alanının toplam baytıdır. **DC3:** dizin girişi
4 baytlık bir belge kimliği sayılır. **DC4:** çekim ekli biçimlerin listesi elle verilmiştir;
sınıflandırma bu on biçimlik tabloya dayanır.

```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/tarama.mjs — ayni soru iki yapida: iliskisel LIKE taramasi ile terimden belgeye
// esleyen ters dizin. Taranan birim, donen kume, fazladan gelen ve kacirilan belge sayilir.
import { DatabaseSync } from "node:sqlite";
import { derlem, BELGE, TOHUM } from "./katalog.mjs";

const db = new DatabaseSync(":memory:");
db.exec("CREATE TABLE kitap(id INTEGER PRIMARY KEY, ad TEXT, ozet TEXT)");
const ekle = db.prepare("INSERT INTO kitap VALUES (?, ?, ?)");
for (const b of derlem) ekle.run(b.id, b.ad, b.ozet);
db.exec("CREATE INDEX kitap_ozet ON kitap(ozet)");           // B-agaci dizini: ozet alani uzerinde
const plan = db.prepare("EXPLAIN QUERY PLAN SELECT id FROM kitap WHERE ozet LIKE ?").all("%deniz%");
const like = (...s) => db.prepare(`SELECT id FROM kitap WHERE ${s.map(() => "ozet LIKE ?").join(" AND ")}`)
  .all(...s.map((x) => `%${x}%`)).map((r) => r.id);

// --- ters dizin: belirtecleme ve Turkce kucuk harf; kok bulma bu derste yok ---
const belirtecle = (s) => s.toLocaleLowerCase("tr").split(/[^\p{L}\p{N}]+/u).filter(Boolean);
const dizin = new Map();
for (const b of derlem) {
  for (const t of new Set(belirtecle(b.ozet))) {
    if (!dizin.has(t)) dizin.set(t, []);
    dizin.get(t).push(b.id);
  }
}
const ara = (...terim) => {
  const liste = terim.map((t) => dizin.get(t) ?? []);
  const en = liste.reduce((a, l) => (l.length < a.length ? l : a));
  return { kume: en.filter((id) => liste.every((l) => l.includes(id))),
    giris: liste.reduce((t, l) => t + l.length, 0) };
};

const bayt = derlem.reduce((t, b) => t + Buffer.byteLength(b.ozet), 0);
console.log(`tohum ${TOHUM}; derlem ${BELGE} belge, ozet alani ${bayt} bayt, dizinde ${dizin.size} terim`);
console.log(`sorgu plani: ${plan[0].detail} — B-agaci dizini varken de her kayit okunuyor`);

const soru = ["deniz", "çocuk"];
const l1 = like(...soru), d1 = ara(...soru);
const CEKIM = new Set(["denizin", "denizler", "denize", "denizden", "denizde",
  "çocuğun", "çocuklar", "çocuğa", "çocuktan", "çocukta"]);   // DC4: bilinen cekim tablosu
const fazla = l1.filter((id) => !d1.kume.includes(id));
const cekimli = fazla.filter((id) => belirtecle(derlem[id - 1].ozet).some((t) => CEKIM.has(t)));
console.log(`\nsoru: ozetinde "${soru.join('" ve "')}" gecen kitaplar`);
console.log(`${"yol".padEnd(16)}${"taranan birim".padStart(15)}${"okunan bayt".padStart(13)}` +
  `${"donen belge".padStart(13)}${"ilk dort kimlik".padStart(20)}`);
console.log("iliskisel LIKE".padEnd(16) + `${BELGE} kayit`.padStart(15) + String(bayt).padStart(13) +
  String(l1.length).padStart(13) + l1.slice(0, 4).join(",").padStart(20));
console.log("ters dizin".padEnd(16) + `${d1.giris} giris`.padStart(15) + String(d1.giris * 4).padStart(13) +
  String(d1.kume.length).padStart(13) + d1.kume.slice(0, 4).join(",").padStart(20));

console.log(`\nLIKE'in fazladan getirdigi ${fazla.length} belge iki turdur:`);
const ornek = (kosul) => fazla.find((id) => kosul(belirtecle(derlem[id - 1].ozet)));
for (const [ad, id] of [["cekim ekli bicim (dizinin kacirdigi)", ornek((t) => t.some((x) => CEKIM.has(x)))],
  ["govde ici baska sozcuk", ornek((t) => !t.some((x) => CEKIM.has(x)))]]) {
  const gecen = belirtecle(derlem[id - 1].ozet).filter((t) => t.includes("deniz") || t.includes("çocuk"));
  console.log(`  ${ad}: #${id} -> ${[...new Set(gecen)].join(", ")}`);
}
console.log(`  ${cekimli.length} belge birinci turden, ${fazla.length - cekimli.length} belge ikinci turden`);

for (const y of ["istanbul", "İstanbul"]) {
  const l = like(y), d = ara(y.toLocaleLowerCase("tr"));
  console.log(`\nsoru "${y}": LIKE ${l.length} belge (${BELGE} kayit tarandi), ` +
    `ters dizin ${d.kume.length} belge (${d.giris} giris tarandi)`);
}
```

```
tohum 20250317; derlem 600 belge, ozet alani 124863 bayt, dizinde 170 terim
sorgu plani: SCAN kitap USING COVERING INDEX kitap_ozet — B-agaci dizini varken de her kayit okunuyor

soru: ozetinde "deniz" ve "çocuk" gecen kitaplar
yol               taranan birim  okunan bayt  donen belge     ilk dort kimlik
iliskisel LIKE        600 kayit       124863           68     237,333,364,490
ters dizin            269 giris         1076           12        8,77,107,118

LIKE'in fazladan getirdigi 59 belge iki turdur:
  cekim ekli bicim (dizinin kacirdigi): #237 -> denizler, çocuklar
  govde ici baska sozcuk: #14 -> deniz, çocukluk
  43 belge birinci turden, 16 belge ikinci turden

soru "istanbul": LIKE 0 belge (600 kayit tarandi), ters dizin 73 belge (73 giris tarandi)

soru "İstanbul": LIKE 73 belge (600 kayit tarandi), ters dizin 73 belge (73 giris tarandi)
```

## Küme Farkı Nereden Geliyor

İki yol aynı soruya farklı yanıt veriyor: LIKE 68 belge, ters dizin 12 belge. Aradaki 59 belge
tek bir nedene indirgenemez, iki ayrı kaynağı vardır ve çıktı ikisini ayrı sayıyor.

Birinci kaynak **çekim ekidir** ve 43 belgeyi kapsar. `#237` numaralı kayıtta özet "denizler" ve
"çocuklar" biçimlerini taşıyor. Okurun sorusu bakımından bu belge ilgilidir; ters dizin onu
kaçırıyor, çünkü bu dersteki dizin sözcüğü olduğu gibi saklıyor ve `denizler` ile `deniz` iki ayrı
terim oluyor. Bu, dizinin bir eksiği değil bir **ayarıdır** — sözcüğün hangi biçimde saklanacağı
üçüncü derste ayrı bir kararla ele alınıyor.

İkinci kaynak **gövde içi eşleşmedir** ve 16 belgeyi kapsar. `#14` numaralı kayıtta "çocuk" geçiyor
ama ikinci koşulu karşılayan şey "çocukluk" sözcüğüdür; `LIKE '%çocuk%'` metnin ortasındaki harf
dizisine bakar, sözcük sınırı tanımaz. Aynı kaynaktan "denizci", "Karadeniz" ve "kitapçı" gibi
sözcükler de eşleşir. Bu belgeler soruya yanlış getirilmiştir ve okuru yanıltır.

Son iki satır kümenin öbür ucunu gösteriyor. `İstanbul` sorusu LIKE ile 73 belge döndürüyor, aynı
sorunun küçük harfle yazılmış hâli **sıfır** belge döndürüyor. Neden Türkçeye özgüdür: `İ` harfinin
küçüğü `i` değil, ASCII dışı bir harftir ve harf katlaması bu çifti tanımaz. Ters dizin iki yazımda
da 73 belge veriyor, çünkü hem dizinlenirken hem sorulurken metin aynı kurala sokuluyor. Arama
motorunun ilişkisel taramadan asıl ayrıldığı yer burasıdır: **yazma ve sorgu zamanında aynı
dönüşümün uygulanması**.

## Sıra ve Bedel

Sıra sütunu üçüncü bir farkı görünür kılıyor. LIKE `237, 333, 364, 490` kimlikleriyle başlıyor;
bu sıra kimlik sırası değildir, sorgu planının seçtiği kapsayan dizinin kendi sırasıdır. Ters dizin
`8, 77, 107, 118` ile başlıyor, yani belge kimliği sırasıyla. İki sıranın ortak yanı şudur:
**hiçbiri seçilmiş bir sıra değildir**. İkisi de yapının depolama düzeninden düşmüştür. Hangi
belgenin daha ilgili olduğu bu kursta ilk kez ikinci konuda soruluyor.

Bedel tarafı da simetrik değildir. LIKE hiçbir hazırlık istemez: kayıt yazıldığı anda aranabilir,
ama her soru 600 kaydı ve 124.863 baytı okur. Ters dizin soruyu 269 giriş okuyarak, yaklaşık
1.076 bayt dokunarak yanıtlar — okunan bayt bakımından yüz on altı katlık bir fark. Karşılığında dizinin **kurulması ve
saklanması** gerekir; her yeni belge dizine işlenmelidir ve bu yapı yer kaplar. Bu dersin ölçtüğü
şey yalnız sorgu tarafıdır; yazma tarafının hesabı sonraki derste bayt bayt çıkarılıyor.

## Özet

- İlişkisel dizin değerin tamamı üzerinde sıralıdır ve `LIKE '%söz%'` sorusuna yardım edemez;
  sorgu planı dizin varken bile `SCAN` gösterir ve 600 kaydın tamamı okunur.
- Ters dizin terimden belgeye gider: aynı soru 269 giriş okunarak yanıtlanır, dokunulan bayt
  124.863'ten 1.076'ya iner.
- İki yolun kümesi aynı değildir: LIKE 68, ters dizin 12 belge döndürür. Aradaki 59 belgenin
  43'ü çekim ekli biçimlerdir (dizinin kaçırdığı), 16'sı gövde içi harf eşleşmesidir (LIKE'ın
  yanlış getirdiği).
- Büyük küçük harf farkı Türkçede kümeyi tamamen çevirir: `istanbul` sorusu LIKE ile 0, `İstanbul`
  sorusu 73 belge döndürür; ters dizin metni yazarken ve sorarken aynı kurala soktuğu için iki
  yazımda da 73 belge verir.
- İki yolun döndürdüğü sıra da seçilmiş bir sıra değildir: biri sorgu planının kullandığı dizinin
  düzeni, öbürü belge kimliği. İlgililik sorusu bu konuda hiç sorulmuyor.

## Sonraki Adım

Bu ders ters dizini bir kara kutu olarak kullandı: terim verildi, belge kimlikleri geldi. Yapının
içinde ne olduğu, kaç bayt tuttuğu ve bir belgenin aynı terimi kaç kez içerdiğinin nerede
saklandığı sorulmadı. Sonraki ders dizini adım adım kuruyor: terim listesi, her terimin altındaki
belge listesi, belge başına terim sayısı ve sözcüğün metindeki konumu. Ölçülen şey bu dört
bileşenin her birinin bayt karşılığı ve konum bilgisinin dizini kaç kat büyüttüğü olacak.
