Ders 06 / 16
Karma Arama
Anahtar sözcük eşleşmesi ile gömme aramasının ayrı ayrı ve birlikte ölçülmesi. Üç kurgu sorgu sınıfında üç kurulum yan yana koşuluyor: abone dilinde anahtar sözcük 0,0500, gömme 0,5000; belge dilinde ikisi de 0,5000; belge kodu sorgusunda anahtar sözcük 1,0000, gömme 0,0000. Sıra temelli birleştirme belge dili sınıfında 0,4000 veriyor, yani ikisinden de kötü; bu sabit 5, 20 ve 60'ta sürüyor. Kod sınıfında birleştirme hedef belgeyi ilk beşte tutma payını 1,0000'den 0,0500'e düşürüyor. Nedeni iki listenin ilk beşinin ortak belge sayısıdır: abone dilinde 0,20, belge dilinde 1,05. İki listede de ikinci sırada duran bir belge, birinde birinci öbüründe yok olan belgeyi geçiyor. Birleştirme yirminci sıraya kadar anmayı 0,7122'den 0,7209'a çıkarıyor; kazandığı yer derinlik, kaybettiği yer ilk sıradır.
İçindekiler
Önceki derste sorgu ile belge arasındaki bağ tek bir yerden kuruldu: gömme vektörlerinin açısı. Süzgeç bu bağı daralttı, değiştirmedi. Oysa bir destek dağarcığında aranan şey her zaman bir anlam değildir. Bir belge kodu, bir hata numarası ya da bir yordamın tam adı arandığında sorulan soru “buna benzer ne var” değil, “bu tam olarak nerede geçiyor” sorusudur. Anlam benzerliği bu sorunun yanından geçer.
Karma arama iki sıralamayı aynı sorgu için birlikte çalıştırıp sonuçlarını tek listede toplamaktır. Beklenti toplamın parçalarından iyi olmasıdır: gömmenin göremediği tam eşleşmeyi anahtar sözcük, anahtar sözcüğün göremediği eş anlamı gömme yakalasın. Bu ders üç kurulumu (yalnız anahtar sözcük, yalnız gömme, birleşik) üç sorgu sınıfında yan yana ölçer. Sonuçlardan biri beklentiyi karşılamaz: bir sorgu sınıfında birleşik, iki yordamdan da kötü kalır.
- GM48. Dağarcık, gömme yordamı, belirteçleyici ve sorgu sınıfları kurgudur; gerçek bir arama motoru, vektör deposu ya da gömme uç noktası çağrılmaz. Tohum 20260218.
- GM49. Belgenin arama metni kodu ile birlikte tutulur. Kod bir kavram yüzeyi olmadığı için gömme vektörünü değiştirmez; blokta gösterilir.
- GM50. Üç sorgu sınıfı aynı belgelerden türetilir ve yalnız yüzeyleri ayrılır: abone dili sorgu yüzeyini, belge dili belge yüzeyini, kod sorgusu belge kodunu taşır. Üçü de kırk sorgudur.
- GM51. Anahtar sözcük sıralaması örtüşen belirteç sayısıdır. İlgililik puanlaması Veritabanları müfredatının Arama Motorları ve Metin Erişimi kursunda kuruldu ve ölçüldü; burada tekrarlanmaz. Bu derste anahtar sözcük tarafının tek işlevi ikinci bir sıralama üretmektir.
- GM52. Birleştirme sıra temellidir: bir belgenin puanı iki listedeki sırasının tersleri
toplamıdır,
1 / (sabit + sıra). Sabit varsayılan olarak 20’dir ve 5 ile 60’ta da sınanır. - GM53. İlk sıra isabeti ilk sonucun hedef kavramı taşıma payı, erişim kesinliği ilk beş sonucun aynı payı, erişim anması hedef kavramı taşıyan belgelerin ilk yirmide yakalanma payıdır. Hedef belge sütunu sorgunun türetildiği belgenin ilk beşte olma payıdır.
- GM54. Her kavramı birden çok belge taşır; bu yüzden kesinlik ve anma farklı derinliklerde okunur ve tek sayıya indirilmez.
- GM55. Üç sıralama da belirlenmiştir: aynı sorgu iki koşumda aynı listeyi verir. Bu dersin koşumdan bağımsız ölçüsü iki listenin ilk beşindeki ortak belge sayısıdır ve sorgudan bağımsız olarak yordam çiftinin bir özelliğidir.
- GM56. Hiçbir kavram yüzeyi taşımayan bir sorgu sıfır vektör üretir; bütün benzerlikler sıfır olur ve sıra saklama sırasına düşer. Bu bir kusur değil, gömmenin tanım alanının dışına çıkmasıdır ve kod sınıfında ölçülür.
- GM57. Bu ders konunun kapanışıdır; getirilen parçanın modele ne yaptığı ölçülmez, sonraki konuya bırakılır.
Üç Sorgu Sınıfı
# KURGU dagarcik, KURGU gomme benzeticisi, KURGU sorgu siniflari. Gercek uc nokta yok. 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): # KURGU belirtecleyici, parca en cok bes damga 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"] 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"]) def _kavramla(m): # yuzey once kavrama cevrilir v = [0.0] * len(ANAHTAR) dm = " " + m.lower() + " " for i, k in enumerate(ANAHTAR): if KAVRAM[k][1] in dm: v[i] += 1.0 if KAVRAM[k][2] in dm: v[i] += 1.0 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): # kavram sonra boyuta dusurulur v = [0.0] * boyut for i, a in enumerate(_kavramla(m)): 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)) K, SABIT = 5, 20 ARAMA = [d["kod"] + " " + metin(d) for d in BELGE] # kod belgenin arama metnine girer VEK = [gom(a) for a in ARAMA] BEL = [set(belirtecle(a)) for a in ARAMA] def sorgular(kip): # ayni belgelerden uc ayri yuzey q = [] for i in range(40): r = uretec(TOHUM + 104729 * i) d = BELGE[int(r() * len(BELGE))] o = ORTAK[int(r() * len(ORTAK))] q.append({"metin": {"abone": f"{KAVRAM[d['ana']][2]} {o}", "belge": f"{KAVRAM[d['ana']][1]} {o}", "kod": f"{d['kod']} numarali belge"}[kip], "kavram": d["ana"], "kod": d["kod"]}) return q SINIFLAR = {k: sorgular(k) for k in ("abone", "belge", "kod")} def anahtar_sira(m): # ortusen belirtec sayisina gore qb = set(belirtecle(m)) return sorted(range(len(BELGE)), key=lambda i: -len(qb & BEL[i])) def gomme_sira(m): qv = gom(m) return sorted(range(len(BELGE)), key=lambda i: -aci(qv, VEK[i])) def birlesik_sira(m, sabit=SABIT): # sira temelli birlestirme pa = {i: 1.0 / (sabit + n) for n, i in enumerate(anahtar_sira(m))} pg = {i: 1.0 / (sabit + n) for n, i in enumerate(gomme_sira(m))} return sorted(range(len(BELGE)), key=lambda i: -(pa[i] + pg[i])) for k, s in SINIFLAR.items(): print(f"{k:6s} ornek sorgu: {s[0]['metin']}") print(f"belge kodu gommeyi degistirmiyor: " f"{gom(ARAMA[0]) == gom(metin(BELGE[0]))} , kod sorgusunun vektor uzunlugu " f"{sum(x * x for x in gom(SINIFLAR['kod'][0]['metin'])):.1f}")
abone ornek sorgu: nasil kaydediliyor form belge ornek sorgu: okuma yordami form kod ornek sorgu: SY194 numarali belge belge kodu gommeyi degistirmiyor: True , kod sorgusunun vektor uzunlugu 0.0
Üç sorgu aynı belgeden türedi ve aynı şeyi soruyor; ayrıldıkları yer yalnız yüzey. Son satır iki şeyi ölçüyor. Belge kodunun arama metnine eklenmesi gömme vektörünü değiştirmiyor: kod bir kavram yüzeyi değil, dolayısıyla gömme onu görmüyor. İkincisi daha sert: kod sorgusunun vektör uzunluğu 0,0. Sorguda tanınan hiçbir kavram olmadığı için vektör sıfırdır, bütün açı benzerlikleri sıfır çıkar ve sıralama saklama sırasına düşer. Gömme bu sorguda yanılmıyor, tanım alanının dışında kalıyor.
Üç Kurulumun Tablosu
def olc(S, sirala): ilk = kes = an = hed = 0.0 for q in S: ilgili = {i for i, d in enumerate(BELGE) if d["ana"] == q["kavram"]} s = sirala(q["metin"]) ilk += s[0] in ilgili kes += len(set(s[:K]) & ilgili) / K an += len(set(s[:20]) & ilgili) / len(ilgili) hed += any(BELGE[i]["kod"] == q["kod"] for i in s[:K]) return [x / len(S) for x in (ilk, kes, an, hed)] YORDAM = (("anahtar", anahtar_sira), ("gomme", gomme_sira), ("birlesik", birlesik_sira)) print("sinif yordam ilk1 kesinlik@5 anma@20 hedef belge@5") for kip, S in SINIFLAR.items(): for ad, f in YORDAM: d = olc(S, f) print(f"{kip:6s} {ad:8s} {d[0]:>6.4f} {d[1]:>11.4f} {d[2]:>8.4f} {d[3]:>15.4f}") print("belge dili sinifinda birlesigin ilk1 degeri , sabit 5 / 20 / 60: " + " / ".join(f"{olc(SINIFLAR['belge'], lambda m, c=c: birlesik_sira(m, c))[0]:.4f}" for c in (5, 20, 60)))
sinif yordam ilk1 kesinlik@5 anma@20 hedef belge@5 abone anahtar 0.0500 0.1200 0.1183 0.0500 abone gomme 0.5000 0.4600 0.7014 0.1500 abone birlesik 0.4500 0.2800 0.4472 0.1250 belge anahtar 0.5000 0.3650 0.6722 0.1750 belge gomme 0.5000 0.4700 0.7122 0.1500 belge birlesik 0.4000 0.4250 0.7209 0.1250 kod anahtar 1.0000 0.2500 0.1950 1.0000 kod gomme 0.0000 0.0800 0.1078 0.0250 kod birlesik 0.0000 0.0850 0.1950 0.0500 belge dili sinifinda birlesigin ilk1 degeri , sabit 5 / 20 / 60: 0.4500 / 0.4000 / 0.4000
İlk iki üçlü karma aramanın gerekçesini kuruyor. Abone dilinde anahtar sözcük 0,0500, gömme 0,5000; kod sorgusunda anahtar sözcük 1,0000, gömme 0,0000. İki yordam aynı dağarcıkta birbirinin tam tersi yerlerde çalışıyor, ve tek bir yordam seçmek sorgu sınıflarından birini tamamen feda etmek demek.
Birleşik satırlar bu feragatin ortadan kalkmadığını gösteriyor. Abone dilinde birleşik 0,4500 ile gömmenin biraz altında; beklenen bedel budur. Belge dilinde ise iki yordam da 0,5000 verirken birleşik 0,4000. Toplam, iki parçasının ikisinden de kötü. Son satır bunun bir sabit seçiminin oyunu olmadığını söylüyor: 5, 20 ve 60’ta 0,4500 / 0,4000 / 0,4000, üçü de 0,5000’in altında.
Kod sınıfı en pahalı satırdır. Anahtar sözcük hedef belgeyi kırk sorgunun kırkında ilk beşe sokuyor; birleşik bunu 0,0500’e düşürüyor. Karma aramanın var olma gerekçesi olan sorgu sınıfında, birleştirme çalışan yordamı çalışmayanla birlikte batırıyor. Sebep tablonun kendi içinde: gömme tarafı bu sınıfta sıfır vektörle çalışıyor ve ürettiği sıra bilgi taşımıyor, ama birleştirme bunu bilmiyor ve o sıraya eşit ağırlık veriyor.
Bir sütun ters yöne bakıyor. Belge dilinde anma@20 anahtar sözcükte 0,6722, gömmede 0,7122, birleşikte 0,7209. Yirminci sıraya kadar birleştirme gerçekten kazandırıyor. Kod sınıfında da anma@20 0,1078’den 0,1950’ye çıkıyor. Birleştirmenin kazandığı yer derinliktir, kaybettiği yer ilk sıradır, ve bir erişim hattında isteme giren şey ilk birkaç parçadır.
Birleştirmenin Kaybettirdiği
print("sinif ilk besin ortak belgesi ikisi dogru birlesik yanlis") for kip, S in SINIFLAR.items(): ortak = kayip = 0 for q in S: ilgili = {i for i, d in enumerate(BELGE) if d["ana"] == q["kavram"]} a, g, b = (f(q["metin"]) for _, f in YORDAM) ortak += len(set(a[:K]) & set(g[:K])) kayip += a[0] in ilgili and g[0] in ilgili and b[0] not in ilgili print(f"{kip:6s} {ortak / len(S):>22.2f} {kayip:>28}") def ilgilisi(q): return {i for i, d in enumerate(BELGE) if d["ana"] == q["kavram"]} q = next(x for x in SINIFLAR["belge"] if anahtar_sira(x["metin"])[0] in ilgilisi(x) and gomme_sira(x["metin"])[0] in ilgilisi(x) and birlesik_sira(x["metin"])[0] not in ilgilisi(x)) print(f"\nsorgu: {q['metin']} -- hedef kavram: {q['kavram']}") for ad, f in YORDAM: print(f" {ad:8s}", [f"{BELGE[i]['kod']}/{BELGE[i]['ana']}" for i in f(q["metin"])[:3]])
sinif ilk besin ortak belgesi ikisi dogru birlesik yanlis abone 0.20 1 belge 1.05 3 kod 4.03 0 sorgu: basinc dususu bolge -- hedef kavram: basinc anahtar ['AR002/basinc', 'AR015/ekip', 'AR018/basinc'] gomme ['AR079/basinc', 'AR088/basinc', 'AR101/ekip'] birlesik ['AR033/ekip', 'AR015/ekip', 'AR018/basinc']
Ortak belge sütunu hiçbir sorguya değil, yordam çiftinin kendisine ait bir sayıdır ve koşumdan bağımsızdır. Abone dilinde iki listenin ilk beşi ortalama 0,20 belge paylaşıyor: yordamlar neredeyse hiç anlaşmıyor. Belge dilinde 1,05, yani beşte bir.
Örnek bu sayının sonucunu gösteriyor. Anahtar sözcük AR002’yi, gömme AR079’u ilk sıraya koyuyor;
ikisi de hedef kavramı taşıyor, yani iki yordam da doğru. Birleşik ilk sıraya AR033’ü koyuyor
ve o belge ekip kavramına ait. AR002 bir listede birinci, öbüründe çok geride; puanı tek bir
büyük terimden geliyor. AR033 ise iki listede de üst sıralarda ama hiçbirinde birinci değil, ve
iki orta terimin toplamı bir büyük terimi geçiyor. Sıra temelli birleştirme uzlaşma belgesini
ödüllendirir; iki taraf aynı fikirde değilken ikisinin de ikinci tercihi kazanır. Belge dili
sınıfında bu kırk sorgunun üçünde oluyor, ve ters yönde hiç olmuyor: birleşiğin, iki yordamın da
yanıldığı bir sorguda doğruyu bulduğu tek bir örnek yok. İlk sıradaki dört sorguluk düşüşün
karşılığı sıfır kazançtır.
Kod satırındaki 4,03 tuzaktır. Yüksek örtüşme burada anlaşma değildir: gömme tarafı sıfır vektörle çalıştığı için listesi saklama sırasıdır, anahtar sözcük tarafının tam eşleşmeden sonraki kuyruğu da aynı sıradır. İki liste aynı bilgisiz kuyruğu paylaşıyor. Birleştirme, iki listenin aynı olmasıyla ikisinin de boş olmasını ayırt edemez; ayırt edebilseydi bu sınıfta anahtar sözcüğe tam ağırlık verirdi. Karma arama bir ortalama değil, bir karar ister: hangi sorguda hangi tarafın söz sahibi olduğu.
Özet
- Üç sorgu sınıfında iki yordam birbirinin tersi yerlerde çalışır: abone dilinde anahtar sözcük 0,0500 ve gömme 0,5000, kod sorgusunda anahtar sözcük 1,0000 ve gömme 0,0000.
- Kavram yüzeyi taşımayan bir sorgu sıfır vektör üretir; gömme yanılmaz, tanım alanının dışına çıkar ve sıralaması saklama sırasına düşer.
- Belge dili sınıfında iki yordam da 0,5000 verirken sıra temelli birleştirme 0,4000 verir; birleşik ikisinden de kötüdür ve bu sabit 5, 20 ve 60’ta sürer.
- Nedeni iki listenin ilk beşinin 1,05 belge paylaşmasıdır: iki listede de ikinci sırada duran uzlaşma belgesi, birinde birinci olup öbüründe bulunmayan belgeyi geçer.
- Kod sınıfında birleştirme hedef belgenin ilk beşte olma payını 1,0000’den 0,0500’e düşürür; bilgisiz bir listeye eşit ağırlık vermek çalışan yordamı da batırır.
- Birleştirme derinlikte kazandırır: belge dilinde anma@20 0,7122’den 0,7209’a çıkar. Kazanç yirminci sırada, kayıp ilk sıradadır ve isteme giren ilk sıradır.
Sonraki Adım
Altı ders boyunca tek bir soru soruldu ve her seferinde daha iyi cevaplandı: dağarcıktaki hangi parça bu sorguya ait. Gömme bir arama anahtarı oldu, alan uyumu ölçüldü, benzerlik ölçütü seçildi, dizinin kaybettirdiği sayıldı, süzgecin komşuluğu bozduğu nokta bulundu ve iki sıralamanın birleşimi tartıldı. Bu derslerin hepsi erişim tarafındadır ve hepsinin ölçüsü getirilen parçanın kendisidir.
Ölçülmeyen şey bundan sonra olandır. Bulunan parça bir isteme konur ve bir modele verilir; o noktadan itibaren doğru parçanın doğru yanıt ürettiği bir varsayımdır ve bu konuda hiç sınanmadı. Doğru parça getirildiği hâlde yanlış yanıt üretilebilir, yanlış parça getirildiği hâlde model şans eseri doğru yanıt verebilir, ve en kötüsü, getirilen parça modelin erişimsiz hâlinden daha kötü bir yanıt üretmesine yol açabilir. Sonraki konu erişim hattını baştan sona kurar ve ilk dersinde iki sütunu ayırır: doğru parça getirildi mi, ve getirilenle doğru yanıt üretildi mi.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.