---
title: 'Benzerlik Ölçütleri'
source: 'https://academia.sh/tr/kurslar/rag/benzerlik-olcutleri'
course: 'Gömme Vektörleri ve Erişim Artırılmış Üretim'
language: tr
updated: '2026-08-17T18:06:35+00:00'
license: 'CC BY-SA 4.0'
---

# Benzerlik Ölçütleri

Aynı vektörlerin iki ayrı ölçütle sıralanması ve seçimin getirilen parçayı ne kadar değiştirdiği. İç çarpım, açı benzerliğinin iki vektörün boyuyla çarpımıdır; bir sorgu için sorgu boyu sabit olduğundan bütün sıra farkı belge vektörünün boyundan gelir ve bu boy en kısa çeyrekte 4,6864, en uzun çeyrekte 5,3966'dır. Kırk sorgunun otuzunda ilk üç sonuç ayrışıyor; açı benzerliği 0,4600 erişim kesinliği ve 0,5000 kavram isabeti verirken iç çarpım 0,3900 ve 0,4250'de kalıyor ve ikinci bir gömme modelinde de aynı yön çıkıyor. Uzunluk yanlılığı iç çarpımdadır: getirilen kümenin ortalaması 64,3 belirteç, açı benzerliğinde 54,6, dağarcıkta 61,5; ilgili belgelerin ortalaması da 61,5 olduğuna göre uzunluk ilgililik taşımıyor.

Önceki iki ders benzerliği hep aynı yordamla hesapladı: vektörler birim uzunluğa getirildi,
sonra karşılıklı koordinatlar çarpılıp toplandı. Birinci adım sessiz bir karardı ve hiç
tartışılmadı. Vektörler birim uzunluğa getirilmezse aynı çarpım başka bir sayı verir ve başka bir
sıralama üretir.

İki ölçüt bu iki durumun adıdır. **Açı benzerliği** iki vektör arasındaki açıyı ölçer ve
uzunluklarını yok sayar. **İç çarpım** koordinat çarpımlarını doğrudan toplar ve uzunluğu içinde
taşır. Aralarındaki bağıntı tek satırdır:

$$\text{iç çarpım}(u, v) = \text{açı benzerliği}(u, v) \cdot \lVert u \rVert \cdot \lVert v \rVert$$

Bir sorgu sabitken $\lVert u \rVert$ bütün belgeler için aynıdır. Buradan çıkan sonuç bu dersin
ekseni: iki ölçüt arasındaki **bütün sıra farkı** $\lVert v \rVert$ değerinden, yani **belge
vektörünün boyundan** gelir.

- **GM18.** Kod **benzeticidir**, dağarcık ve gömme yordamı **kurgudur**, tohum **20260218**.
  Boyut otuz iki, getirilen parça beş, ilgili belge tanımı önceki iki dersle aynı, gömme alan içi.
- **GM19.** **Tek vektör kümesi, iki ölçüt.** Paylaşılan gömme yordamı vektörü birim uzunluğa
  getirir, ham yordam getirmez; açı benzerliği birim vektörlerin iç çarpımıdır.
- **GM20.** Yukarıdaki bağıntı blokta **sayıyla denetlenir**.
- **GM21.** Belge uzunluğu **belirteç sayısıyla** ölçülür; dağarcıkta otuz iki ile doksan altı
  arası değişiyor.
- **GM22. Ayrışma** ilk **üç** sonucun **kümesi** üzerinden sayılır: iki ölçüt aynı üç belgeyi
  getiriyorsa sıraları farklı olsa bile ayrışmamış sayılır.
- **GM23.** **Uzunluk yanlılığı iki tabana karşı okunur**: getirilen kümenin ortalama belirteci
  dağarcık ortalamasına, ilk beşte en uzun çeyreğin payı o çeyreğin dağarcıktaki payına karşı.
- **GM24.** Koşumdan bağımsız ölçü **aynı aileden ikinci bir gömme modelidir** (izdüşüm tohumu
  20260219). Sıralama iki modelde aynı yönde çıkmazsa **ölçülmüş sayılmaz**.

## Tek Vektör Kümesi, İki Ölçüt

İlk blok dağarcığı kurar, normalleştirilmemiş vektörü üreten yordamı ekler ve iki şeyi gösterir:
belge vektörünün boyu uzunlukla nasıl büyüyor, ve bağıntı tutuyor mu.

```python
# BENZETICI -- KURGUDUR. Gercek bir gomme uc noktasi cagrilmaz. Dagarcik,
# kavram ekseni, gomme yordami ve sorgu kumesi KURGUDUR; hicbir gercek
# kurum, urun ya da belge degildir.
TOHUM, M32 = 20260218, 0xFFFFFFFF
BOYUT = 32


def uretec(t):
    x = ((t ^ (t >> 16)) * 2246822507) & M32
    x = ((x ^ (x >> 13)) * 3266489909) & M32
    s = [(x ^ (x >> 16)) & M32]

    def sonraki():
        s[0] = (s[0] * 1664525 + 1013904223) & M32
        return s[0] / 4294967296
    return sonraki


def ayrik(u, w):
    t = 0.0
    for i, x in enumerate(w):
        t += x
        if u < t:
            return i
    return len(w) - 1


def belirtecle(m):
    b = []
    for s in m.lower().replace(",", " , ").split():
        while len(s) > 5:
            b.append(s[:5])
            s = s[5:]
        b.append(s)
    return b


# ---- KURGU anlam ekseni: her kavramin belge dilinde ve sorgu dilinde ayri yuzeyi var
SINIF = ["tarife", "ariza", "sayac", "kesinti", "bakim"]
KOD = {"tarife": "TR", "ariza": "AR", "sayac": "SY", "kesinti": "KS", "bakim": "BK"}
KAVRAM = {                       # kavram: (sinif, belge yuzeyi, sorgu yuzeyi)
    "basamak":   ("tarife", "kademe esigi", "hangi dilimdeyim"),
    "birim":     ("tarife", "birim ucret", "metrekup fiyati"),
    "abonetip":  ("tarife", "abone tipi", "mesken mi isyeri mi"),
    "gecis":     ("tarife", "tarife gecisi", "plan degistirme"),
    "arizakod":  ("ariza", "ariza kodu", "hata numarasi"),
    "sizinti":   ("ariza", "hat sizintisi", "su kacagi"),
    "basinc":    ("ariza", "basinc dususu", "zayif akis"),
    "ekip":      ("ariza", "saha ekibi", "gorevli ne zaman gelir"),
    "endeks":    ("sayac", "endeks degeri", "sayac ustundeki rakam"),
    "okuma":     ("sayac", "okuma yordami", "nasil kaydediliyor"),
    "degisim":   ("sayac", "sayac degisimi", "cihaz yenileme"),
    "dogrula":   ("sayac", "okuma dogrulamasi", "yanlis girilmis mi"),
    "planli":    ("kesinti", "planli kesinti", "onceden duyurulan durma"),
    "duyuru":    ("kesinti", "duyuru kanali", "nereden ogrenirim"),
    "sure":      ("kesinti", "kesinti suresi", "ne kadar surer"),
    "geridonus": ("kesinti", "yeniden verme", "ne zaman gelir"),
    "periyot":   ("bakim", "periyodik bakim", "duzenli kontrol"),
    "vana":      ("bakim", "vana kontrolu", "musluk kapatma duzeni"),
    "filtre":    ("bakim", "filtre degisimi", "temizleme parcasi"),
    "kalib":     ("bakim", "kalibrasyon kaydi", "olcum ayari"),
}
ANAHTAR = list(KAVRAM)
ORTAK = ["kayit", "bolge", "donem", "islem", "form", "onay", "not"]

# ---- KURGU dagarcik
BELGE = []
for i in range(200):
    r = uretec(TOHUM + 7919 * i)
    s = SINIF[ayrik(r(), [0.22, 0.24, 0.20, 0.18, 0.16])]
    kav = [k for k in ANAHTAR if KAVRAM[k][0] == s]
    ana = kav[int(r() * len(kav))]
    n = 2 + int(r() * 4)
    par, kavlar = [], [ana]
    for _ in range(n):
        y = kav[int(r() * len(kav))]
        kavlar.append(y)
        o = ORTAK[int(r() * len(ORTAK))]
        par.append(f"{KAVRAM[y][1]} icin {o} tutulur ve {KAVRAM[ana][1]} ile birlikte yazilir")
    BELGE.append({"kod": f"{KOD[s]}{i + 1:03d}", "sinif": s, "ana": ana, "kavram": kavlar,
                  "baslik": f"{KAVRAM[ana][1]} yordami", "par": par})


def metin(d):
    return d["baslik"] + " " + " ".join(d["par"])


# ---- KURGU gomme: yuzey once kavrama, kavram sonra boyuta dusuruluyor
def _kavramla(m, alan=True):
    v = [0.0] * len(ANAHTAR)
    dm = " " + m.lower() + " "
    for i, k in enumerate(ANAHTAR):
        bel, sor = KAVRAM[k][1], KAVRAM[k][2]
        if bel in dm:
            v[i] += 1.0
        if sor in dm:
            v[i] += 1.0 if alan else 0.0      # alan disi gomme sorgu dilini tanimaz
    if not alan:
        for o in ORTAK:
            if " " + o + " " in dm:
                for i in range(len(ANAHTAR)):
                    v[i] += 0.05
    return v


IZDUS = []
for i in range(len(ANAHTAR)):
    r = uretec(TOHUM ^ (i + 1) * 2654435761)
    IZDUS.append([r() * 2 - 1 for _ in range(64)])


def gom(m, boyut=BOYUT, alan=True):
    k = _kavramla(m, alan)
    v = [0.0] * boyut
    for i, a in enumerate(k):
        if a:
            for j in range(boyut):
                v[j] += a * IZDUS[i][j % 64]
    n = sum(x * x for x in v) ** 0.5
    return [x / n for x in v] if n else v


def aci(a, b):
    return sum(x * y for x, y in zip(a, b))


# ---- KURGU sorgu kumesi: sorgu dili belge dilinden ayri
SORGU = []
for i in range(40):
    r = uretec(TOHUM + 104729 * i)
    d = BELGE[int(r() * len(BELGE))]
    SORGU.append({"metin": f"{KAVRAM[d['ana']][2]} {ORTAK[int(r() * len(ORTAK))]}",
                  "sinif": d["sinif"], "kavram": d["ana"]})

# Iki olcut, tek vektor kumesi: paylasilan gom() vektoru birim uzunluga getirir,
# ham() getirmez. Aci benzerligi birim vektorlerin ic carpimidir.
def ham(m, boyut=BOYUT, alan=True):
    k = _kavramla(m, alan)
    v = [0.0] * boyut
    for i, a in enumerate(k):
        if a:
            for j in range(boyut):
                v[j] += a * IZDUS[i][j % 64]
    return v


def uzunluk(v):
    return sum(x * x for x in v) ** 0.5


BELIRTEC = [len(belirtecle(metin(d))) for d in BELGE]
NORM = [uzunluk(ham(metin(d))) for d in BELGE]
sirali = sorted(range(len(BELGE)), key=lambda i: BELIRTEC[i])
c = len(BELGE) // 4
kisa, uz = sirali[:c], sirali[-c:]
print(f"dagarcik: belirtec ortalamasi {sum(BELIRTEC) / len(BELGE):.1f} ,"
      f" en kisa {BELIRTEC[sirali[0]]} , en uzun {BELIRTEC[sirali[-1]]}")
print(f"  en kisa ceyrek : ortalama {sum(BELIRTEC[i] for i in kisa) / c:.1f} belirtec ,"
      f" ham vektor uzunlugu {sum(NORM[i] for i in kisa) / c:.4f}")
print(f"  en uzun ceyrek : ortalama {sum(BELIRTEC[i] for i in uz) / c:.1f} belirtec ,"
      f" ham vektor uzunlugu {sum(NORM[i] for i in uz) / c:.4f}")
q, d = SORGU[0], BELGE[0]
qh, bh = ham(q["metin"]), ham(metin(d))
print(f"\nozdeslik denetimi , sorgu 1 ile {d['kod']}:")
print(f"  ic carpim                  {aci(qh, bh):.6f}")
print(f"  aci benzerligi             {aci(gom(q['metin']), gom(metin(d))):.6f}")
print(f"  aci * iki vektorun boyu    "
      f"{aci(gom(q['metin']), gom(metin(d))) * uzunluk(qh) * uzunluk(bh):.6f}")
```

```
dagarcik: belirtec ortalamasi 61.5 , en kisa 32 , en uzun 96
  en kisa ceyrek : ortalama 37.7 belirtec , ham vektor uzunlugu 4.6864
  en uzun ceyrek : ortalama 85.8 belirtec , ham vektor uzunlugu 5.3966

ozdeslik denetimi , sorgu 1 ile BK001:
  ic carpim                  -0.218248
  aci benzerligi             -0.011168
  aci * iki vektorun boyu    -0.218248
```

Çeyrek satırları mekanizmayı veriyor. En kısa çeyrekte belge ortalama 37,7 belirteç ve ham vektör
boyu 4,6864; en uzun çeyrekte 85,8 belirteç ve 5,3966. Belge iki buçuk katına çıkarken boy yalnız
yüzde on beş büyüyor, ama iç çarpım o boyla **çarpıldığı** için bu yüzde on beş doğrudan puana
giriyor. Nedeni yordamda yazılı: bir belge ne kadar çok kavram anıyorsa kavram vektörüne o kadar
çok ağırlık düşüyor.

Özdeşlik denetimi bağıntının tuttuğunu gösteriyor: iç çarpım doğrudan hesaplandığında ve açı
benzerliği iki boyla çarpıldığında altı basamağa kadar aynı sayı çıkıyor. İki ölçüt ayrı yordamlar
değil; **biri öbürünün boylarla çarpılmış hâlidir**.

## Ölçüt Değişince Sıra Ne Kadar Değişiyor

Aşağıdaki blok aynı kırk sorguyu iki ölçütle koşturur ve bunu iki gömme modelinde tekrarlar. Her
model için önce ilk üç sonucu ayrışan sorgu sayısı, sonra dört erişim ölçüsü ve getirilen kümenin
ortalama belirteci basılır.

```python
K = 5
ILGILI = {k: sum(1 for d in BELGE if d["ana"] == k) for k in ANAHTAR}

# Ayni aileden ikinci gomme modeli: yalniz izdusum tohumu farkli (20260219).
IZDUS2 = []
for i in range(len(ANAHTAR)):
    r = uretec((TOHUM + 1) ^ (i + 1) * 2654435761)
    IZDUS2.append([r() * 2 - 1 for _ in range(64)])


def ham2(m, boyut=BOYUT):
    k = _kavramla(m)
    v = [0.0] * boyut
    for i, a in enumerate(k):
        if a:
            for j in range(boyut):
                v[j] += a * IZDUS2[i][j % 64]
    return v


def birim(v):
    n = uzunluk(v)
    return [x / n for x in v] if n else v


def diz(qv, vek):
    return sorted(range(len(BELGE)), key=lambda i: (-aci(qv, vek[i]), i))


def olc(gomucu):
    hv = [gomucu(metin(d)) for d in BELGE]
    av = [birim(v) for v in hv]
    sayi = {"aci": [0.0] * 5, "ic carpim": [0.0] * 5}
    ayrisan = 0
    for q in SORGU:
        qh = gomucu(q["metin"])
        a, b = diz(birim(qh), av), diz(qh, hv)
        ayrisan += set(a[:3]) != set(b[:3])
        for ad, ust in (("aci", a[:K]), ("ic carpim", b[:K])):
            t = sum(BELGE[i]["ana"] == q["kavram"] for i in ust)
            s = sayi[ad]
            s[0] += t / K
            s[1] += t / ILGILI[q["kavram"]]
            s[2] += BELGE[ust[0]]["ana"] == q["kavram"]
            s[3] += BELGE[ust[0]]["sinif"] == q["sinif"]
            s[4] += sum(BELIRTEC[i] for i in ust) / K
    n = len(SORGU)
    return ayrisan, {ad: [x / n for x in s] for ad, s in sayi.items()}


for etiket, gomucu in (("model 1", ham), ("model 2", ham2)):
    ayrisan, sonuc = olc(gomucu)
    print(f"{etiket} : ilk uc sonucu ayrisan sorgu {ayrisan}/{len(SORGU)}")
    print("  olcut      kesinlik    anma  kavram   sinif  ortalama belirtec")
    for ad, s in sonuc.items():
        print(f"  {ad:<10} " + " ".join(f"{x:7.4f}" for x in s[:4]) + f" {s[4]:15.1f}")
```

```
model 1 : ilk uc sonucu ayrisan sorgu 30/40
  olcut      kesinlik    anma  kavram   sinif  ortalama belirtec
  aci         0.4600  0.2223  0.5000  1.0000            54.6
  ic carpim   0.3900  0.1879  0.4250  0.9500            64.3
model 2 : ilk uc sonucu ayrisan sorgu 27/40
  olcut      kesinlik    anma  kavram   sinif  ortalama belirtec
  aci         0.4050  0.2035  0.5250  1.0000            52.6
  ic carpim   0.3400  0.1680  0.3500  0.9500            57.9
```

İlk satır ölçüt seçiminin bir ayrıntı olmadığını söylüyor: kırk sorgunun **otuzunda** iki ölçüt
farklı bir ilk üçlü getiriyor. Aynı vektörler, aynı dağarcık, aynı sorgular; değişen tek şey
puanın normalleştirilmiş vektörlerden mi ham vektörlerden mi okunduğu.

Dört ölçüde açı benzerliği her sütunda önde: kesinlik 0,4600'e karşı 0,3900, anma 0,2223'e karşı
0,1879, kavram isabeti 0,5000'e karşı 0,4250, sınıf isabeti 1,0000'e karşı 0,9500. İkinci gömme
modelinde sayılar değişiyor ama **yön değişmiyor**: 0,4050'ye karşı 0,3400 ve 0,5250'ye karşı
0,3500. Ölçüt sıralaması tek bir izdüşümün çekilişi değil.

Son sütun farkın nereden geldiğini gösteriyor. Açı benzerliğinin getirdiği beş belgenin ortalaması
54,6 belirteç, iç çarpımınki 64,3. Aradaki 9,7 belirteçlik kayma bir yan ürün değil, ölçütün
tanımının doğrudan sonucudur.

## Uzunluğun İlgililik Taşımadığı Yerde Uzunluğa Bakmak

Bir kaymanın yanlılık sayılabilmesi için uzunluğun **ilgililik taşımadığının** gösterilmesi
gerekir. Aşağıdaki blok iki tabanı basar: dağarcığın ortalama uzunluğu ile ilgili belgelerin
ortalama uzunluğu, ve en uzun çeyreğin iki ölçütün ilk beşindeki payı.

```python
c = len(BELGE) // 4
enuzun = set(sorted(range(len(BELGE)), key=lambda i: -BELIRTEC[i])[:c])
ilg = {k: [i for i, d in enumerate(BELGE) if d["ana"] == k] for k in ANAHTAR}
print(f"dagarcik ortalamasi {sum(BELIRTEC) / len(BELGE):.1f} belirtec ,"
      f" en uzun ceyregin payi {c / len(BELGE):.4f}")
print("ilgili belgelerin ortalamasi %.1f belirtec"
      % (sum(sum(BELIRTEC[i] for i in ilg[q["kavram"]]) / len(ilg[q["kavram"]])
             for q in SORGU) / len(SORGU)))
hv = [ham(metin(d)) for d in BELGE]
av = [birim(v) for v in hv]
print("\nolcut      ilk beste en uzun ceyregin payi")
for ad, vek, qf in (("aci", av, lambda q: birim(ham(q["metin"]))),
                    ("ic carpim", hv, lambda q: ham(q["metin"]))):
    p = sum(sum(1 for i in diz(qf(q), vek)[:K] if i in enuzun) / K
            for q in SORGU) / len(SORGU)
    print(f"{ad:<10} {p:32.4f}")
```

```
dagarcik ortalamasi 61.5 belirtec , en uzun ceyregin payi 0.2500
ilgili belgelerin ortalamasi 61.5 belirtec

olcut      ilk beste en uzun ceyregin payi
aci                                  0.0800
ic carpim                            0.2500
```

İlk iki satır kararı veriyor. Dağarcığın ortalaması 61,5 belirteç; ilgili belgelerin ortalaması da
61,5. Uzunluk ile ilgililik arasında bu dağarcıkta bir bağ yok, yani uzun bir belgenin sorguya
yanıt verme şansı kısa bir belgeden fazla değil.

Alt tablo bunun sıralamaya nasıl yansıdığını yazıyor. En uzun çeyrek dağarcığın 0,2500'ünü
oluşturuyor. İç çarpımın ilk beşinde bu çeyreğin payı **0,2500**, yani taban oranın tam kendisi;
açı benzerliğinin ilk beşinde **0,0800**, yani taban oranın üçte birinden az. İki ölçüt uzunluğa
karşı iki ayrı yerde duruyor: iç çarpım uzun belgeleri dağarcıktaki paylarında tutuyor, açı
benzerliği onları eliyor.

Elemenin niçin işe yaradığı boyun tanımından okunur. Uzun belge daha çok kavram anıyor; ham
vektörü daha uzun ama **daha dağınık**. Açı benzerliği boyu bölerek attığı için kalan soru "kaç
kavram anılmış" değil, "hangi kavrama ne oranda yer verilmiş" oluyor; sorgu tek bir kavramı
hedeflediğine göre kazanan yoğunlaşmış belge oluyor.

Buradan çıkan sonuç ölçüt adlarından bağımsızdır. **Bütün vektörler birim uzunluktaysa iki ölçüt
aynı sıralamayı verir**; boylar bire eşit olduğunda çarpım hiçbir şeyi değiştirmez. Asıl karar
"hangi ölçüt" değil, **vektörler saklanırken normalleştiriliyor mu** kararıdır. Normalleştirme
yapılıyorsa iç çarpım bir bölme işleminden tasarruf eder ve sonuç aynıdır; yapılmıyorsa ölçüt
seçimi kırk sorgunun otuzunda getirilen parçayı değiştirir.

## Özet

- İç çarpım, açı benzerliğinin iki vektörün boyuyla çarpımıdır; sabit bir sorguda bütün sıra farkı
  belge vektörünün boyundan gelir.
- Belge vektörünün boyu uzunlukla büyür: en kısa çeyrekte 4,6864, en uzun çeyrekte 5,3966.
- Kırk sorgunun otuzunda iki ölçüt farklı bir ilk üçlü getiriyor.
- Açı benzerliği dört ölçüde de önde (0,4600 / 0,2223 / 0,5000 / 1,0000 karşısında 0,3900 / 0,1879
  / 0,4250 / 0,9500) ve ikinci gömme modelinde yön aynı kalıyor.
- Uzunluk yanlılığı iç çarpımdadır: getirilen kümenin ortalaması 64,3 belirteç, açı benzerliğinde
  54,6, dağarcıkta 61,5; en uzun çeyreğin ilk beşteki payı 0,2500 ile 0,0800.
- İlgili belgelerin ortalaması da 61,5 belirteçtir, yani uzunluk ilgililik taşımaz; vektörler birim
  uzunlukta saklanıyorsa iki ölçüt aynı sıralamayı verir.

## Sonraki Adım

Üç derste erişimin üç kararı ölçüldü: sözcük mü anlam mı, hangi gömme modeli, hangi ölçüt. Üçünde
de ortak kalan ve hiç sorulmayan bir şey vardı: her sorgu **bütün dağarcıkla** karşılaştırıldı,
kırk sorgu ve iki yüz belge için 8000 karşılaştırma yapıldı, tam sıralama her seferinde baştan
kuruldu. İki yüz belgede bu bir sorun değil; dağarcık yüz binlerce parçaya çıktığında her sorgu
için bütün vektörlere dokunmak sürdürülemez. Sonraki ders vektörleri bir **dizin** içine koyar ve
tam taramayı taban alarak sorar: bütün belgelere dokunmadan getirilen küme dokunularak
getirilenden ne kadar sapıyor ve karşılaştırma sayısı karşılığında hangi anma veriliyor.
