---
title: 'Düğüm Rolleri'
source: 'https://academia.sh/tr/kurslar/arama-motorlari/dugum-rolleri'
course: 'Arama Motorları ve Metin Erişimi'
language: tr
updated: '2026-08-17T18:09:01+00:00'
license: 'CC BY-SA 4.0'
---

# Düğüm Rolleri

Aramanın tek süreçten kümeye taşınması: veri, eşgüdüm ve ana düğümlerin ayrılması, aynı üç yüz sorgunun iki rol yerleşiminde koşturulup her düğümün okuduğu gönderi girişi ile yaptığı birleştirme adımının sayılması, parça sayısı artarken veri işinin bölünüp eşgüdüm işinin bölünmediğinin gösterilmesi ve ana düğüm rolünün yüklü bir veri düğümüne bindirilmesinin küme durumunu geciktirerek dönen belge kümesiyle ilk beş sonucun sırasını değiştirmesinin ölçülmesi.

Önceki konu bütün sorguları tek bir süreçte ve tek bir dizin üzerinde koşturdu: sorgu
değerlendirici gönderi listelerini doğrudan okuyordu ve dönen sıra puanlayıcının hesapladığı
sıranın kendisiydi. Katalog büyüdüğünde bu düzenek iki yerinden kırılır — dizin tek bir
makinenin belleğine sığmaz olur ve tek bir süreç gelen sorgu hızına yetişemez. Dizin birden
çok makineye yayıldığında sorgunun kendisi değişmez; değişen, sorguyu kimin karşıladığı,
gönderi listelerini kimin okuduğu ve dönen adayları kimin birleştirdiğidir. Bu ders o üç işi
üç role ayırır ve rollerin küme üzerine nasıl dağıtıldığının neyi değiştirdiğini sayar.

## Üç Rol

**Veri düğümü** bir parçayı taşır: o parçanın ters dizini onun belleğindedir. Sorgu geldiğinde
yalnızca kendi parçasını tarar ve kendi yerel sırasının ilk adaylarını döndürür.

**Eşgüdüm düğümü** sorguyu karşılar, her parçaya birer istek gönderir, dönen aday listelerini
birleştirir ve son listeyi çıkarır; kendisi gönderi listesi okumaz.

**Ana düğüm** sorgu yolunda hiç yer almaz. Taşıdığı şey küme durumudur: hangi parçanın hangi
düğümde olduğu, hangi eşlemenin geçerli olduğu, bir düğüm eklendiğinde parçaların nereye
atanacağı. Bu durumun yeni sürümünü kümeye yayabilen tek düğüm odur.

Aşağıdaki düzenek bu üç rolü **süreç içinde modeller**: düğümler aynı süreçte nesnelerdir, ağ
ve ileti gecikmesi yoktur. Model olduğu için ölçtüğü şey süre değil, her düğümün yaptığı iştir —
okunan gönderi girişi ve yapılan birleştirme adımı, ikisi de koşumdan bağımsız.

**AK1 — sorgu karışımı dört katalog sorusundan oluşur ve 300 tur boyunca eşit paylıdır.**
**AK2 — bir küme durumu değişikliğinin uygulanması 500 iş birimi tutar, dizinleme hızı 20 iş
birimi başına bir belgedir.** İki varsayım da doğrusal etkilidir: değerler değişirse aşağıdaki
gecikme ve reddedilen belge sayısı aynı oranda değişir.

```js
// kume/derlem.mjs — kutuphane katalogu derlemi ve ters dizin. Uretec kendi yazilmistir, tohum
// gorunurdur: her kosumda ayni 4000 kayit cikar. Dizin bir sozluk tutar: terim -> gonderi
// listesi; gonderi burada bir belge girisidir (belge kimligi + terim sikligi).
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);

export 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;
}

export function dizinle(belge) {
  const gonderi = new Map(), uzunluk = new Map();
  let bayt = 0;
  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, []); bayt += x.length + 4; }
      gonderi.get(x).push([d.id, n]); bayt += 8;
    }
  }
  const ort = [...uzunluk.values()].reduce((a, b) => a + b, 0) / (belge.length || 1);
  return { gonderi, uzunluk, N: belge.length, ort, bayt };
}

// Puanlama: terim sikligi, ters belge sikligi ve belge uzunlugu. YEREL puanlamada df ve ortalama
// uzunluk yalniz bu dizinden okunur; kuresel verilirse butun derlemin istatistigi kullanilir.
export function ara(dz, terim, k, kuresel = null) {
  const N = kuresel ? kuresel.N : dz.N, ort = kuresel ? kuresel.ort : dz.ort, puan = new Map();
  let taranan = 0;
  for (const t of terim) {
    const g = dz.gonderi.get(t) ?? [];
    const df = kuresel ? kuresel.df.get(t) ?? 0 : 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 };
}

// k-yollu birlestirme: her adimda parca listelerinin basi karsilastirilir, en yuksek puanli
// alinir. Adim sayisi gercek karsilastirma sayisidir ve makineden bagimsizdir.
export function birlestir(liste, k) {
  const konum = liste.map(() => 0), sonuc = [];
  let adim = 0, en = 0;
  while (sonuc.length < k && en >= 0) {
    en = -1;
    for (let i = 0; i < liste.length; i += 1) {
      const a = liste[i][konum[i]], b = en < 0 ? null : liste[en][konum[en]];
      if (!a) continue;
      adim += 1;
      if (!b || a.p > b.p || (a.p === b.p && a.id < b.id)) en = i;
    }
    if (en >= 0) { sonuc.push(liste[en][konum[en]]); konum[en] += 1; }
  }
  return { sonuc, adim };
}
```

```js
// kume/roller.mjs — ana, veri ve esgudum dugumlerinin sorgu basina yaptigi is. Kume SUREC ICI
// BIR MODELDIR: dugumler ayni surecte nesnelerdir, ag yoktur. Olculen sey sure degil, okunan
// gonderi girisi ile yapilan birlestirme adimidir; ikisi de is birimi sayilir.
import { derlem, dizinle, ara, birlestir } from "./derlem.mjs";

const P = 4, KP = 10, K = 10, TUR = 300, DURUM_ISI = 500, BELGE_ISI = 20, YENI = 800;
const SORGU = [["kisa", "oyku", "yalnizlik"], ["deniz", "liman", "gemi"],
  ["masal", "resimli", "cocuk"], ["arsiv", "belge", "yuzyil"]];
const s = (x, n) => String(x).padStart(n);
const parcala = (b, p) => Array.from({ length: p }, (_, i) => dizinle(b.filter((d) => d.id % p === i)));

// Bir sorgu turu: esgudum dugumu her parcaya gider, parca basina KP yerel aday toplar, birlestirir.
function sorgula(dizin, terim, esgudum, is) {
  const liste = [];
  for (let i = 0; i < dizin.length; i += 1) {
    const r = ara(dizin[i], terim, KP);
    is[`d${i}`] = (is[`d${i}`] ?? 0) + r.taranan;
    liste.push(r.aday);
  }
  const b = birlestir(liste, K);
  is[esgudum] = (is[esgudum] ?? 0) + b.adim;
  return { sonuc: b.sonuc, aday: liste.reduce((t, l) => t + l.length, 0), adim: b.adim };
}

const belge = derlem(), tam = dizinle(belge), dizin = parcala(belge, P), yuk = {};
console.log(`${belge.length} belge, ${P} parca, parca basina ${KP} aday, son liste ${K}. Tohum 20260731.`);
console.log(`tek parcali dizin: ${tam.gonderi.size} terim, ${tam.bayt} bayt. Sorgu turu: ${TUR},`);
console.log(`esgudum dugumune ulasan aday: ${TUR * P * KP}.\n`);
console.log("yerlesim        | dugum | roller           | is birimi | pay");
console.log("----------------|-------|------------------|-----------|------");
for (const ayri of [false, true]) {
  const is = {}, esgudum = ayri ? "e0" : "d0";
  for (let t = 0; t < TUR; t += 1) sorgula(dizin, SORGU[t % SORGU.length], esgudum, is);
  const dugum = ayri ? ["a0", "e0", "d0", "d1", "d2", "d3"] : ["d0", "d1", "d2", "d3"];
  const rol = (n) => n === "a0" ? "ana" : n === "e0" ? "esgudum"
    : (n === "d0" && !ayri) ? "ana+veri+esgudum" : "veri";
  const toplam = dugum.reduce((t, n) => t + (is[n] ?? 0), 0);
  yuk[ayri ? "ayri" : "birlesik"] = is;
  for (const n of dugum)
    console.log(`${(ayri ? "roller ayri" : "roller birlesik").padEnd(15)} | ${n.padEnd(5)} | ${rol(n).padEnd(16)} | ` +
      `${s(is[n] ?? 0, 9)} | ${s("%" + (100 * (is[n] ?? 0) / toplam).toFixed(1), 5)}`);
}

console.log("\nesgudum dugumunun sorgu basina isi (ayni derlem, parca sayisi degisiyor):");
console.log("parca | toplanan aday | birlestirme adimi | esgudum payi | veri dugumu basina taranan giris");
for (const p of [1, 2, 4, 8, 16]) {
  const is = {}, r = sorgula(parcala(belge, p), SORGU[0], "e0", is);
  const veri = Object.entries(is).filter(([n]) => n !== "e0").reduce((t, [, v]) => t + v, 0);
  console.log(`${s(p, 5)} | ${s(r.aday, 13)} | ${s(r.adim, 17)} | ` +
    `${s("%" + (100 * r.adim / (veri + r.adim)).toFixed(1), 12)} | ${s(Math.round(veri / p), 32)}`);
}

// Ana dugum sorgu yolunda yer almaz; kume durumunu yayar. 150. sorgudan sonra besinci parca
// istenirse, ana rolu bir veri dugumune bindirildiginde bu is o dugumun sorgu kuyrugunun
// arkasina gecer. Atama uygulanana kadar yeni parcaya yonlenecek belgeler reddedilir.
console.log(`\nana dugumun yeri: 150. sorgudan sonra besinci parca isteniyor, ${YENI} yeni kayit bekliyor`);
console.log("yerlesim        | ana dugumun kuyrugu | durum gecikmesi | reddedilen | dizinlenen belge | eslesen | ilk 5 sonuc");
const genis = derlem({ adet: 4000 + YENI });
for (const ayri of [false, true]) {
  const kuyruk = ayri ? 0 : Math.round(yuk.birlesik.d0 * (TUR - 150) / TUR);
  const gecikme = kuyruk + DURUM_ISI;
  const red = Math.min(YENI, Math.floor(gecikme / BELGE_ISI));
  const kayit = genis.filter((d) => d.id <= 4000 || d.id > 4000 + red);
  const dz = parcala(kayit, red === YENI ? P : P + 1), is = {};
  const son = sorgula(dz, SORGU[0], "e0", is);
  const eslesen = dz.reduce((t, x) => t + ara(x, SORGU[0], K).eslesen, 0);
  console.log(`${(ayri ? "roller ayri" : "roller birlesik").padEnd(15)} | ${s(kuyruk, 19)} | ${s(gecikme, 15)} | ` +
    `${s(red, 10)} | ${s(kayit.length, 16)} | ${s(eslesen, 7)} | ${son.sonuc.slice(0, 5).map((x) => x.id).join(" ")}`);
}
console.log(`\nkosumdan bagimsiz: esgudum dugumu sorgu basina P x ${KP} aday toplar. Parca eklendikce` +
  ` veri dugumu basina is bolunur, esgudum dugumunun isi bolunmez.`);
```

```
4000 belge, 4 parca, parca basina 10 aday, son liste 10. Tohum 20260731.
tek parcali dizin: 80 terim, 382752 bayt. Sorgu turu: 300,
esgudum dugumune ulasan aday: 12000.

yerlesim        | dugum | roller           | is birimi | pay
----------------|-------|------------------|-----------|------
roller birlesik | d0    | ana+veri+esgudum |     94875 | %27.4
roller birlesik | d1    | veri             |     78375 | %22.6
roller birlesik | d2    | veri             |     89100 | %25.7
roller birlesik | d3    | veri             |     84150 | %24.3
roller ayri     | a0    | ana              |         0 |  %0.0
roller ayri     | e0    | esgudum          |     12000 |  %3.5
roller ayri     | d0    | veri             |     82875 | %23.9
roller ayri     | d1    | veri             |     78375 | %22.6
roller ayri     | d2    | veri             |     89100 | %25.7
roller ayri     | d3    | veri             |     84150 | %24.3

esgudum dugumunun sorgu basina isi (ayni derlem, parca sayisi degisiyor):
parca | toplanan aday | birlestirme adimi | esgudum payi | veri dugumu basina taranan giris
    1 |            10 |                10 |         %0.8 |                             1238
    2 |            20 |                20 |         %1.6 |                              619
    4 |            40 |                40 |         %3.1 |                              310
    8 |            80 |                80 |         %6.1 |                              155
   16 |           160 |               160 |        %11.4 |                               77

ana dugumun yeri: 150. sorgudan sonra besinci parca isteniyor, 800 yeni kayit bekliyor
yerlesim        | ana dugumun kuyrugu | durum gecikmesi | reddedilen | dizinlenen belge | eslesen | ilk 5 sonuc
roller birlesik |               47438 |           47938 |        800 |             4000 |     515 | 2689 701 2181 3159 1777
roller ayri     |                   0 |             500 |         25 |             4775 |     624 | 3159 3544 2689 701 2362

kosumdan bagimsiz: esgudum dugumu sorgu basina P x 10 aday toplar. Parca eklendikce veri dugumu basina is bolunur, esgudum dugumunun isi bolunmez.
```

## Sorgu Başına İş Nereye Düşüyor

İlk tablo aynı 300 sorguyu iki rol yerleşiminde koşturuyor ve **aynı sonucu döndürüyor**: iki
yerleşim de aynı parça dizinlerini okuduğu için dönen belge kümesi ve sıra birebir aynıdır.
Değişen, işin nereye düştüğüdür.

Roller birleşikken sorgular tek bir giriş noktasına, d0'a geliyor; d0 hem kendi parçasını
tarıyor hem de bütün birleştirmeyi yapıyor. 94.875 iş birimiyle kümenin yüzde 27,4'ünü
taşıyor, en hafif düğüm d1 ise yüzde 22,6. Aradaki 12.000 birimlik fark eşgüdüm işinin tam
kendisidir; roller ayrıldığında o birimler e0'a geçiyor ve d0 82.875 birime iniyor.

İkinci satır grubunda ana düğümün payı **yüzde 0,0** çıkıyor: 300 sorgu boyunca a0 tek bir
gönderi girişi okumadı ve tek bir karşılaştırma yapmadı. Ana düğümün yükü sorgu sayısıyla
değil, **küme durumunun değişme sıklığıyla** artar.

## Eşgüdüm İşi Bölünmez

İkinci tablo aynı derlemi 1, 2, 4, 8 ve 16 parçaya bölüp tek bir sorguyu koşturuyor. İki sütun
ters yönde hareket ediyor. Veri düğümü başına taranan gönderi girişi 1238'den 77'ye iniyor —
parça sayısıyla tam olarak bölünüyor, çünkü aynı gönderi listeleri parçalara dağılıyor. Buna
karşılık eşgüdüm düğümünün topladığı aday ve yaptığı birleştirme adımı 10'dan 160'a çıkıyor:
her parça kendi ilk on adayını göndermek zorundadır ve birleştirici her sonuç için bütün liste
başlarını karşılaştırır.

Eşgüdüm payının yüzde 0,8'den 11,4'e çıkması bu iki eğrinin bileşkesidir: parça eklemek ucuz
olan tarafı böler, pahalı olan tarafı tek düğümde toplar.

## Ana Düğümün Yeri Kümeyi Değiştiriyor

Üçüncü tablo 150. sorgunun ardından kümeye beşinci bir parça eklenmesini istiyor; 800 yeni
katalog kaydı bu parçaya yönlenmeyi bekliyor. Ana rolü d0'a bindirildiğinde durum değişikliği o
düğümün sorgu kuyruğunun arkasına düşüyor: 47.438 birimlik birikmiş sorgu işi, ardından 500
birimlik durum işi. AK2'nin dizinleme hızıyla bu, 800 kaydın tamamının reddedilmesi demektir ve
derlem 4000 belgede kalıyor. Ana rolü ayrı düğümdeyken gecikme 500 birim, reddedilen kayıt 25;
dizin 4775 belgeye çıkıyor.

Fark sorgu sonucunda görünüyor. Aynı sorgu — kısa öykü konusunda yalnızlık geçen kayıtlar —
birleşik yerleşimde 515, ayrık yerleşimde 624 belgeyle eşleşiyor: 109 belge fark. İlk beş
sonuç da aynı değil. Birleşik yerleşimde sıra 2689, 701, 2181, 3159, 1777; ayrık yerleşimde
3159, 3544, 2689, 701, 2362. Üç belge ortak, ama hiçbiri aynı basamakta değil ve listenin iki
üyesi tamamen değişiyor. Rol yerleşimi bir sorgu ayarı değildir; buna karşın dönen kümeyi ve
sırayı değiştirir, çünkü hangi belgelerin dizine girebildiğini belirler.

## Özet

- Üç rol üç ayrı işe karşılık gelir: veri düğümü gönderi listesi okur, eşgüdüm düğümü aday
  toplayıp birleştirir, ana düğüm küme durumunu yayar ve sorgu yolunda yer almaz.
- Rollerin ayrılması dönen kümeyi ve sırayı değiştirmedi; 300 sorguda 12.000 iş birimini d0'dan
  eşgüdüm düğümüne taşıdı ve en yüklü düğümün payı yüzde 27,4'ten 25,7'ye indi. Aynı koşumda ana
  düğümün payı yüzde 0,0 kaldı: yükü sorgu sayısıyla değil, durum değişikliğiyle artar.
- Parça sayısı 1'den 16'ya çıktığında veri düğümü başına taranan giriş 1238'den 77'ye indi,
  eşgüdüm düğümünün adayı ve birleştirme adımı 10'dan 160'a, payı yüzde 0,8'den 11,4'e çıktı.
- Ana rolü yüklü bir veri düğümüne bindirildiğinde durum değişikliği 47.938 birim gecikti ve
  800 kaydın tamamı reddedildi; ayrı düğümde gecikme 500 birim, reddedilen 25 kayıt oldu. Bu
  gecikme sorguya geçti: eşleşen belge 515'e karşı 624 ve ilk beşin sırası tamamen değişti.

## Sonraki Adım

Bu ders parça sayısını sabit tuttu ve her parçadan sabit sayıda aday çekti; iki sayının da
seçilmiş olduğu sorgulanmadı. Daha ağır bir soru açık kaldı: her parça kendi ilk on adayını
**kendi yerel istatistiğiyle** seçiyor ve birleştirici bu yerel puanlara güveniyor. Parça
sayısı arttıkça her parçanın ölçtüğü belge sıklığı küresel değerden uzaklaşır ve seçtiği
adaylar değişir. Sonraki ders parça sayısını 1'den 16'ya çıkarıp ilk on sonucun tek parçalı
dizinin ilk onundan ne kadar saptığını sayar, buna kopya sayısının dizin boyutuna ve düğüm
kaybına etkisini ekler.
