“GTM datalayer debug” diye arıyorsun. Keyword search “GTM” ve “datalayer” kelimelerini içeren dokümanları buluyor. Ama “etkinlik verilerinin izlenmesinde sorun giderme” başlıklı, tam senin aradığın dokümanı bulamıyor, çünkü o kelimeler geçmiyor.
Vector search ile arıyorsun. Embedding modeli “GTM datalayer debug” ile “etkinlik verilerinin izlenmesinde sorun giderme” arasındaki anlamsal benzerliği yakalıyor. Ama bu sefer “GTM” kısaltmasını içeren konfigürasyon dosyasını kaçırıyor, çünkü embedding 3 harflik kısaltmayı anlamsal olarak eşleştiremiyor.
İkisini birlikte çalıştırdığında, ikisinin de güçlü olduğu sonuçlar üste çıkıyor. Bu, hybrid search.
Keyword Search: BM25 ile Kelime Eşleştirme
BM25 (Best Matching 25) bir metin arama algoritması. Temel mantığı basit ama etkili:
- Kelime sıklığı (TF): Aranan kelime dokümanda ne kadar sık geçiyorsa, skor o kadar yükselir
- Doküman uzunluğu normalizasyonu: Uzun dokümanlar sırf uzun oldukları için yüksek skor almasın diye düzeltme yapılır
- Ters doküman sıklığı (IDF): Kelime koleksiyondaki her dokümanda geçiyorsa (örneğin “ve”, “bir”), değeri düşer. Nadir kelimeler daha değerli
SQLite’ın built-in FTS5 (Full-Text Search 5) modülü BM25 scoring kullanır. Ayrı bir sunucu gerektirmez, veritabanı dosyasının içinde çalışır.
Ne zaman güçlü?
- Kısaltmalar: “GTM”, “sGTM”, “CAPI”, “RRF”
- Değişken/fonksiyon adları:
handleSubmit,datalayer.push - Hata kodları: “ERR_CONNECTION_REFUSED”, “404”
- Exact phrase: “consent mode v2 advanced”
Ne zaman zayıf?
- Eş anlamlılar: “performans” ararken “hız” veya “speed” dönemez
- Çapraz dil: “sepet terk” ararken “cart abandonment” bulamaz
- Kavramsal sorgu: “kullanıcı neden sayfadan ayrılıyor?” gibi soyut sorularda
Vector Search: Embedding ile Anlam Eşleştirme
Embedding, metni yüksek boyutlu bir vektöre (sayı dizisi) dönüştürür. “Sepet terk oranı” ve “cart abandonment rate” farklı kelimeler ama embedding uzayında birbirine yakın noktalarda bulunur.
Benzerlik ölçümü cosine similarity ile yapılır: iki vektör arasındaki açının kosinüsü. 1.0 = birebir aynı yön, 0.0 = ilişkisiz, -1.0 = zıt.
dnomia-knowledge intfloat/multilingual-e5-base modeli kullanıyor (768 boyut, çok dilli). sqlite-vec eklentisi SQLite’a KNN (K-Nearest Neighbors) vektör araması ekliyor.
Ne zaman güçlü?
- Anlamsal sorgu: “tracking neden çalışmıyor?” ararken debug rehberini bulur
- Çapraz dil: Türkçe soru, İngilizce doküman (veya tersi)
- Kavramsal benzerlik: “veri kaybı” ararken “data loss prevention” döner
Ne zaman zayıf?
- Kısaltmalar: “GTM” için embedding çok genel, spesifik eşleşme zayıf
- Yeni/nadir terimler: Modelin eğitim verisinde olmayan kelimeler
- Exact match: “consent_mode_v2” gibi teknik terimlerde keyword daha isabetli
Hybrid Search: İkisini Birleştirmek
İki arama motoru farklı güçlere sahip. Hybrid search ikisini birlikte çalıştırıp sonuçları birleştirir.
Reciprocal Rank Fusion (RRF)
RRF, iki farklı sıralı listeyi tek bir sıralı listeye birleştirmenin yöntemi. Formül:
RRF_score(d) = Σ 1 / (k + rank_i(d))
k sabiti genellikle 60 (orijinal paper’daki değer). rank_i(d) dokümanın i. listesindeki sırası.
Somut örnek:
BM25 sonuçları: 1. dosya-A, 2. dosya-C, 3. dosya-B
Vector sonuçları: 1. dosya-B, 2. dosya-A, 3. dosya-D
RRF birleştirme (k=60):
dosya-A: 1/(60+1) + 1/(60+2) = 0.0164 + 0.0161 = 0.0325
dosya-B: 1/(60+3) + 1/(60+1) = 0.0159 + 0.0164 = 0.0323
dosya-C: 1/(60+2) + 0 = 0.0161
dosya-D: 0 + 1/(60+3) = 0.0159
Final sıralama: dosya-A, dosya-B, dosya-C, dosya-D
İki arama motorunun “oy kullanması” gibi düşün. İkisi de yüksek sıralıyorsa, doküman kesinlikle ilgili. Sadece birinde yüksekse, yine listeye girer ama daha aşağıda.
Neden basit skor ortalaması değil?
BM25 skoru ve cosine similarity farklı ölçeklerde. BM25 0-25 arası, cosine 0-1 arası. Doğrudan ortalama almak büyük ölçeği (BM25) dominant kılar. RRF sıralama bazlı çalıştığı için ölçek farkından etkilenmez.
Chunk Boyutu: Küçük ve Odaklı Kazanır
Hybrid search’ün etkinliği doğrudan chunk kalitesine bağlı. Burada kritik bir bulgu var:
340 karakterlik odaklı bir kural, hedef sorgusu için 0.57 similarity skoru aldı. Aynı bilgiyi içeren 1.5KB çok konulu bir doküman, aynı sorgu için 0.25 skor aldı1.
2.3 kat fark. Aynı bilgi, farklı paketleme. Neden?
Embedding modeli tüm chunk’ı tek bir vektöre sıkıştırır. Chunk büyüdükçe, her kavram daha az temsil edilir. 340 karakterlik chunk “consent mode v2 advanced modda cookie yazılmaz ama cookieless ping gönderilir” dediğinde, embedding tam bu anlama odaklanır. 1.5KB’lık doküman aynı cümleyi içerse bile, diğer 20 cümle embedding’i sulandırır.
dnomia-knowledge heading bazlı chunking kullanıyor: ## ve ### başlıklarında bölüyor, minimum 200 karakter birleştirme uyguluyor. Bu, her chunk’ın tek bir konuya odaklı olmasını sağlıyor.
Structured Matching: TF-IDF Bazen Daha İyi
Her şey embedding gerektirmiyor. Yapılandırılmış eşleşmelerde (skill routing, tag matching, exact kategori eşleştirme) TF-IDF, embeddings’ten 250 kat daha verimli olabiliyor2.
Neden? Embedding modeli yüklemek, çalıştırmak ve inference yapmak computational olarak pahalı. “Bu sorgu hangi skill’e gitmeli?” gibi bir routing kararında, anahtar kelime eşleştirmesi (TF-IDF) milisaniyede cevap verirken, embedding modeli yüzlerce milisaniye sürer.
Kural: embedding karmaşık, anlamsal sorular için. Keyword/TF-IDF yapısal, kategorik eşleştirmeler için.
Pratik Uygulama: dnomia-knowledge
dnomia-knowledge bu hybrid yaklaşımı SQLite üzerinde tek dosyada uyguluyor:
SQLite veritabanı (tek .db dosyası)
├── FTS5 tablosu (BM25 keyword search)
├── sqlite-vec tablosu (vector KNN search)
└── chunk tablosu (metadata, dosya yolu, proje)
Arama akışı:
Sorgu geldi: "GTM consent mode debug"
↓
1. FTS5 arama (BM25): "GTM", "consent", "mode", "debug" kelimelerini ara
→ Sonuç: [chunk-A (skor 12.3), chunk-C (skor 8.1), chunk-E (skor 5.2)]
↓
2. Vector arama (cosine): sorguyu embed et, en yakın chunk'ları bul
→ Sonuç: [chunk-B (skor 0.82), chunk-A (skor 0.74), chunk-D (skor 0.68)]
↓
3. RRF birleştirme (k=60): iki listeyi sıralama bazlı birleştir
→ Final: [chunk-A (0.0325), chunk-B (0.0323), chunk-C (0.0161), ...]
chunk-A iki listede de üst sıralarda, en ilgili sonuç. chunk-B sadece vector’da güçlü (anlamsal benzerlik), chunk-C sadece keyword’de güçlü (kelime eşleşmesi). İkisi de listeye giriyor ama chunk-A’nın altında.
Performans
- FTS5 arama: < 1ms (SQLite native, indeksli)
- Vector arama: < 10ms (sqlite-vec, 768 boyut, birkaç bin chunk)
- Embedding üretimi: ~50ms/sorgu (multilingual-e5-base, CPU)
- Toplam: ~60ms/sorgu
Ayrı Elasticsearch + Pinecone kurulumu gerektirmez. Tek SQLite dosyası, tek Python process.
Prefix Kuralı
intfloat/e5 modeli prefix gerektirir:
- Sorgular:
"query: GTM consent mode debug" - Dokümanlar:
"passage: Bu rehberde consent mode v2 yapılandırması..."
Prefix olmadan similarity skorları düşer. Model bu prefix’lere göre eğitilmiş, sorgu ve doküman vektörlerini farklı uzaylara haritalıyor.
Fallback Stratejisi
Bazen hybrid search bile sonuç döndürmez. dnomia-knowledge üç katmanlı fallback kullanıyor:
- Hybrid search (RRF): İlk deneme, en iyi sonuçlar
- Prefix fallback: Sonuç yoksa, sorgu terimlerinin başlangıç eşleşmesiyle ara (GTM → “GTM server”, “GTM preview”)
- Sadece FTS5: Vector sonuç döndürmezse, keyword sonuçlarını tek başına döndür
Bu, “hiç sonuç yok” durumunu minimize ediyor.
Ne Zaman Hangi Yaklaşım?
| Senaryo | En İyi Yaklaşım | Neden |
|---|---|---|
| Kısaltma/kod arama | BM25 (keyword) | Exact match kritik |
| ”Bu neden çalışmıyor?” | Vector (embedding) | Anlamsal benzerlik gerekli |
| Genel arama | Hybrid (RRF) | İkisinin güçlü yanlarını birleştir |
| Skill routing | TF-IDF | Hız ve verimlilik |
| Çapraz dil arama | Vector (embedding) | Multilingual model dil bariyerini aşar |
Sonuç
Hybrid search, “ya keyword ya vector” ikileminden çıkış yolu. RRF ile birleştirme, iki farklı gücü tek bir sıralamaya dönüştürüyor.
Ama teknoloji seçimi kadar chunk kalitesi de önemli. 340 karakter odaklı bilgi, 1.5KB dağınık dokümandan 2.3 kat daha etkili. Arama motorunu iyileştirmeden önce, arama yapılacak veriyi iyileştirmek genellikle daha büyük etki yaratır.
Chunk kalitesinin bir üst seviyesi ise chunk’ı tamamen ortadan kaldırmak. jCodeMunch, Tree-sitter AST parsing ile kod sembollerini (fonksiyon, sınıf, import) doğrudan indeksliyor ve byte-offset ile O(1) erişim sağlıyor. Chunk-based RAG’da fonksiyonun ortasından bölünme riski varken, symbol-based retrieval tam bir mantıksal birim döndürüyor. FastAPI codebase’inde chunk RAG 330K token + %74 precision verirken, symbol retrieval 480 token + %96 precision veriyor3. Kod aramasında chunk’lamak yerine AST’den symbol çıkarmak, metin aramasında hybrid search’ün yaptığını bir adım ileriye taşıyor.
Kaynak kodu: dnomia-knowledge (MIT lisans, SQLite + FTS5 + sqlite-vec + RRF)
Footnotes
- Memory Vault shared brain çalışması. 340 karakter focused rule vs 1.5KB multi-topic document similarity karşılaştırması. Kaynak: dev.to/tars_mistaike ↩
- Skill resolver token economics. TF-IDF vs embeddings structured matching benchmark. Kaynak: dev.to/comeonoliver ↩
- Gravelle, J. (2026). Bringing The Receipts: 95% AI LLM Token Savings. Dev.to. jCodeMunch: Tree-sitter AST parsing ile symbol-level code retrieval. FastAPI benchmark: chunk RAG 330K token / %74 precision vs symbol retrieval 480 token / %96 precision. 15 task, 3 repo üzerinden ortalama %95 token azalma. ↩
- 01 BM25 (keyword) kelimeleri eşleştirir, TF-IDF ağırlıklı. Kısaltmalar, değişken adları, hata kodları için güçlü.
- 02 Vector search (embedding) anlamsal benzerliği yakalar. 'sepet terk oranı' ararken 'cart abandonment rate' döner.
- 03 İkisi birlikte çalıştığında birbirinin zayıf noktasını kapatır. RRF ile birleştirme, sonuç listelerini sıralama bazlı puanlıyor.
- 04 Chunk boyutu kritik: 340 karakter odaklı kural 0.57 similarity, 1.5KB çok konulu doküman 0.25. Küçük ve odaklı her zaman kazanır.
- 05 Yapılandırılmış eşleşmelerde (skill routing, tag matching) TF-IDF embeddings'ten 250 kat daha verimli olabiliyor.
+ BM25 nedir?
Best Matching 25, bir metin arama algoritması. Kelimenin dokümandaki sıklığına, doküman uzunluğuna ve koleksiyondaki nadirliğine bakarak skor hesaplar. Google'ın ilk yıllarında temel arama mantığı olarak kullanıldı.
+ Embedding search nedir?
Metni yüksek boyutlu bir vektöre dönüştürüp, vektörler arası mesafe (cosine similarity) ile benzerlik ölçen arama yöntemi. 'Anlam' bazlı çalışır: farklı kelimelerle ifade edilen aynı kavramı bulabilir.
+ RRF (Reciprocal Rank Fusion) nedir?
İki farklı arama sonucunu birleştirme yöntemi. Her sonuç listesinde bir dokümanın sırasına göre puan verir: 1/(k+sıra). k genellikle 60. İki listede de üst sıralarda olan dokümanlar en yüksek puanı alır.
+ Neden sadece vector search kullanmıyoruz?
Vector search anlamı yakalar ama exact match'te zayıf. 'GTM' ararken, embedding 'Google Tag Manager' ile 'tag management' arasında ayrım yapamayabilir. BM25 ise 'GTM' kısaltmasını doğrudan eşleştirir.
+ SQLite ile vector search yapılabilir mi?
Evet. sqlite-vec eklentisi SQLite'a vector arama yeteneği ekler. FTS5 zaten built-in. İkisi aynı veritabanında, ayrı sunucu gerektirmeden çalışır.