İçeriğe geç
wedevit

31 Ağustos 2026 · 9 dk okuma · yazılım

İlhan Buğra Aslan

Kullanıcı aradığını bulamıyor: site içi arama neden kötü çalışır?


Site içi arama çoğu yerde teknik olarak çalışıyor ama işe yaramıyor, ve sebep neredeyse her zaman aynı üç şeyden biri. Sorgu veritabanına LIKE '%kelime%' olarak gidiyor, dolayısıyla ortada sıralama diye bir şey yok. Kullanıcının yazdığı ile katalogdaki metin birebir tutmuyor (yazım hatası, Türkçe ek, eksik şapka) ve sonuç boş dönüyor. Kimse arama günlüğüne bakmadığı için hangi sorguların boş döndüğü bilinmiyor. İlk ikisi çoğu zaman motor değiştirmeden düzelir. Üçüncüsünü düzeltmeden başlarsanız, para verdiğiniz yeni arama motoru büyük olasılıkla aynı kötü sonuçları daha hızlı döndürür.

İlk iş motor seçmek değil, sorgu günlüğü tutmak

Aramayı iyileştirme işine girenlerin çoğu ürün karşılaştırmasıyla başlıyor. Doğru başlangıç noktası kendi kullanıcılarınızın ne yazdığı. Her aramada şu beş alanı kaydedin: sorgu metni, dönen sonuç sayısı, kullanıcının tıkladığı sonucun sırası (tıklamadıysa bunu da), uygulanan filtreler ve aramadan sonra oturumun ne olduğu.

Bu veriden dört gösterge çıkar. Boş dönen sorgu oranı en bilinen ama en yanıltıcı olan, çünkü sonuç dönüp de hepsi alakasız olan aramalar bu orana hiç yansımaz. Tıklamasız arama oranı ondan daha iyi bir sinyal. Aramadan sonra siteyi terk etme oranı en sert olan. Dördüncüsü, arama yapan oturumların dönüşüm oranını hiç arama yapmayanlarla kıyaslamak. Sağlıklı bir sitede arama yapan kullanıcı daha yüksek dönüşür, çünkü niyeti nettir; tersi çıkıyorsa arama kutusu satış kaybediyor demektir.

Sorgu dağılımı hemen her sitede uzun kuyruklu olur: ilk birkaç yüz sorgu hacmin büyük kısmını taşır, geri kalan binlerce farklı sorgu kuyruğu oluşturur. Bu iyi haber, çünkü ilk 200 sorguyu elle gözden geçirmek bir öğleden sonralık iştir ve etkisi tahmin ettiğinizden büyüktür. Baymard Institute'un e-ticaret arama kıyaslamasına göre incelenen sitelerin yüzde 56'sı "vasat ya da daha kötü" arama deneyimi sunuyor, yani bu işi düzeltmek hâlâ bir fark yaratma alanı.

Kullanıcılar tek tip sorgu yazmıyor

Aramayı "ürün adının bir parçasını yazar, ürünü bulur" varsayımıyla kurmak en yaygın hata. Baymard'ın sorgu tipi araştırması sekiz farklı davranış tanımlıyor ve sitelerin zorlandığı oranlar birbirinden çok farklı:

  • Birebir arama (ürün adı, model kodu, dışarıdan kopyalanmış metin): sitelerin yüzde 12'sinde sorunlu.
  • Ürün tipi ("sandalet", "dizüstü bilgisayar"): yüzde 20.
  • Özellik ("deri ceket", "5 litre kova"): yüzde 39.
  • Belirti ("boğaz ağrısı", "halıda leke"): yüzde 37.
  • Kullanım amacı ("düğün hediyesi", "oyun bilgisayarı"): yüzde 43.
  • Uyumluluk ("Dell şarj aleti", "iPhone 15 kılıf"): yüzde 44.
  • Kısaltma ve simge ("13 inç laptop", "-5 derece uyku tulumu"): yüzde 54.
  • Ürün dışı ("iade koşulları", "kargo ne zaman gelir"): yüzde 66.

Son satır en çok atlanan yer. Arama indeksinize yalnızca ürünleri koyduysanız, "iade" yazan kullanıcı boş sonuç ekranı görüyor, oysa aradığı sayfa sitede duruyor. Sayfaları, sık sorulan soruları ve blog içeriğini de indekse alın, sonuç ekranında ayrı bir blok olarak gösterin. Uyumluluk ve kısaltma sorguları ise veri işi: ürün verisinde "13,3 inç" yazıyorsa kullanıcının yazdığı 13", 13 inch ve 13in biçimlerini eşanlamlı olarak tanımlamanız gerekir.

LIKE '%kelime%' neden duvara çarpar

Baştaki joker karakter yüzünden bu sorgu normal bir B-tree indeksinden faydalanamaz, tablo büyüdükçe maliyeti doğrusal artar. Daha kötüsü sonucun ikili olması: kayıt ya eşleşir ya eşleşmez, elinizde sıralayacak bir alaka puanı yoktur, o yüzden sonuçlar isme ya da kimliğe göre dizilir. Alt dizi mantığı da beklenmedik yerlerden ısırır. "el" arayan kullanıcı elbiseyi, jeli ve kelepçeyi aynı listede görür.

Postgres'te bunun kısmi bir çaresi var. pg_trgm uzantısıyla gin_trgm_ops kullanan bir GIN indeksi, PostgreSQL 9.1'den beri LIKE ve ILIKE, 9.3'ten beri de düzenli ifade aramalarını hızlandırabiliyor. Yani tarama hızlanır. Ama sıralama, Türkçe ek yönetimi ve eşanlamlı desteği hâlâ ortada yoktur. İndeks ve sorgu planı tarafında neyin niçin yavaş olduğunu veritabanı darboğazları yazısında ayrıntılı ele almıştık.

Postgres ile nereye kadar gidilir

Tam metin arama Postgres'in içinde var ve çoğu iç uygulama, kurumsal panel ve orta ölçekli katalog için fazlasıyla yeterli. Kurulum kalıbı basit: aranacak alanları birleştiren bir tsvector üretilen sütunu (PostgreSQL 12 ve sonrası) ve üstüne bir GIN indeksi. Üretilen sütun ifadesinin değişmez olması gerektiği için to_tsvector'ı iki argümanlı biçimde, dil yapılandırmasını açıkça yazarak kullanmanız şart.

Kullanıcı girdisini sorguya çevirirken websearch_to_tsquery tercih edin. Belgelendirmenin açıkça belirttiği üzere bu fonksiyon sözdizimi hatası üretmez, yani ham kullanıcı metnini doğrudan verebilirsiniz; tırnak içi ifadeyi öbek aramasına, OR kelimesini "veya" işlemine, baştaki tireyi olumsuzlamaya çevirir. to_tsquery'ye elle metin birleştirmek ise ilk garip karakterde hata fırlatan bir uç nokta demektir.

Türkçe tarafında iyi haber şu: Postgres'in Snowball sözlükleri arasında Türkçe kök bulucu geliyor, ayrı bir kurulum gerektirmiyor. Sınırları da net ve belgelenmiş. ts_rank hiçbir küresel bilgi kullanmadığı için nadir kelimelere ağırlık veremez ve puanları yüzdeye normalize etmek mümkün değildir. Sıralama, eşleşen her kaydın tsvector değerini okumayı gerektirdiğinden geniş sonuç kümelerinde girdi çıktı sınırlıdır. Yazım hatası toleransı yoktur. Eşanlamlı sözlüğü, faset sayımları ve öneri listesi sizin işinizdir.

Yazım hatası toleransı iki farklı yerden gelir

Postgres'te kaldıysanız pg_trgm ikinci katman olarak iyi çalışır. Benzerlik eşiği öntanımlı olarak 0,3'tür, % operatörü bu eşiğe göre karar verir, <% kelime benzerliğine bakar, <-> ise mesafe döndürdüğü için ORDER BY içinde kullanılabilir. Pratik kalıp: önce tam metin arama, sıfır sonuç dönerse trigram sorgusuna düşme. Böylece "termostad" yazan kullanıcı termostatı bulur.

Ayrı arama motorları bunu varsayılan davranış olarak verir. Meilisearch öntanımlı olarak beş karakter ve üzeri kelimelerde bir, dokuz karakter ve üzerinde iki yazım hatasını tolere eder. Typesense'te num_typos öntanımlı 2 ve üst sınır da 2, çünkü tolere edilen hata sayısı arttıkça hesap maliyeti hızla büyür.

Buradaki tuzak, toleransın her alanda iyi bir fikir olduğunu sanmak. Model kodlarında ve parça numaralarında yazım hatası toleransı doğrudan zarar verir: "A15" ile "A16" arasında bir karakter fark vardır ve kullanıcı yanlış yedek parçayı sipariş eder. İki motor da bunun için alan bazlı ayar sunuyor, kod alanlarında toleransı kapatın.

Türkçe'nin üç tuzağı

Noktalı ve noktasız i. Küçük harfe çevirme işlemi dile bağlıdır. Türkçe kurallarında I harfinin küçüğü ı, İngilizce kurallarında i'dir. Veritabanınız ya da arama motorunuz yanlış dil kuralıyla çalışıyorsa "IŞIK" katalogda "işik" olarak indekslenir ve "ışık" arayan kullanıcı hiçbir şey bulamaz. Elasticsearch'ün hazır turkish analizörü tam bu yüzden turkish_lowercase süzgecini içeriyor. Postgres'te sonuç veritabanının derlem ayarına bağlıdır, varsaymak yerine tek satırlık bir sorguyla test edin.

Şapkasız yazım. Kullanıcı klavyeyle boğuşmak istemez, "ogrenci", "cocuk", "sirket" yazar. Çözüm unaccent benzeri bir uzantı ya da ICU normalizasyonu, fakat kritik nokta şu: aynı normalizasyonu hem indeksleme hem sorgu tarafında uygulamak zorundasınız. Yalnızca birinde uygularsanız durumu iyileştirmek yerine bozarsınız.

Ekler. Türkçe eklemeli bir dil, "arabalarımızdan" tek kelime. Hem Postgres'in Snowball sözlüğü hem Elasticsearch'ün Türkçe analizörü kök bulma yapıyor, ama bu araçlar kaba çalışır ve zaman zaman alakasız kelimeleri aynı köke indirir. Marka ve ürün adlarını kök bulmadan korumak için anahtar kelime işaretleyicisi kullanın; Elasticsearch'ün Türkçe analizöründe turkish_keywords süzgeci bunun için var.

Üçünü de kurcalamaya başlamadan önce gerçek günlüğünüzden 100 sorgu seçip beklenen ilk üç sonucu elle yazın. Her yapılandırma değişikliğinden sonra bu seti çalıştırın. Aksi hâlde bir sorguyu düzeltirken üç tanesini bozduğunuzu ancak müşteri söyleyince öğrenirsiniz.

Alaka düzeyi bir ayar değil, karar listesi

"Alaka düzeyini iyileştirin" cümlesi tek başına iş tanımı değil. Sıralamayı açık kurallar hâlinde yazın: model kodu ya da stok kodu birebir tutuyorsa o kayıt daima birinci. Sonra metin puanı. Sonra iş kuralları: stokta olan öne, kampanyalı öne, tükenmiş arkaya. Popülerlik en sonda ve sınırlı ağırlıkla, çünkü genel popülerlik sorguya özgü isabetli sonucu bastırmaya başladığı anda arama, kategori sayfasının kötü bir kopyasına dönüşür.

Eşanlamlı listesi de kod değil içeriktir, ürün ekibinin sahiplenmesi gerekir. "Notebook" ile "dizüstü", "cep telefonu" ile "telefon", yaygın marka yazım hataları, birim varyasyonları. Bu liste sorgu günlüğünden büyür ve hiç bitmez. Boş dönen sorgular listesi de sizin ürün ekibine gidecek en değerli belgedir: talep var, karşılık yok.

Aramanın sessizce sızdırdığı şeyler

Arama indeksi genelde ana veritabanının bir kopyasıdır ve yetki kontrolleri o kopyaya taşınmaz. Klasik kaza: taslak kayıtlar, yayından kaldırılmış ürünler, müşteriye özel fiyat listeleri ya da başka bir kiracının verisi indekste durur ve doğru kelimeyi yazan herkes onları görür. Filtrelemeyi arayüzde değil sorgunun kendisinde yapın, kiracı ve yetki alanlarını indekse yazıp her sorguya zorunlu filtre olarak ekleyin. Modelin nasıl kurulacağı yetkilendirme yazısında duruyor.

Otomatik tamamlama önerilerini kullanıcı sorgularından üretiyorsanız ikinci bir sızıntı kapısı açılır. İnsanlar arama kutusuna sipariş numarası, telefon, hatta e-posta yazar. Öneri listesini yalnızca eşik değeri geçen, temizlenmiş ve onaylanmış sorgulardan üretin.

Ayrı motora geçme eşiği

Postgres'te kalmak şu koşullarda mantıklı: katalog birkaç yüz bin kaydın altında, arama sitenin ana gezinme yolu değil, faset sayımlarına ve anlık yazarken arama deneyimine ihtiyaç yok, ekip yeni bir sistemi işletmek istemiyor. Ayrı motora geçmek şu koşullarda mantıklı: arama satışın ana kanalı, çok dilli katalog var, sıralama kuralları haftalık değişiyor, milyonlarca kayıt ya da yüksek eşzamanlı sorgu hacmi söz konusu.

Kararın gerçek maliyeti motorun kendisi değil, indeks senkronizasyonu. Üç yaklaşım var. Çift yazma en kolayıdır ve zamanla mutlaka kayar. Belirli aralıkla tam yeniden indeksleme güvenlidir ama veriyi bayatlatır. Değişiklik yakalama ya da giden mesaj tablosu doğru olanıdır ve en çok iş isteyendir. Hangisini seçerseniz seçin bir bayatlık bütçesi belirleyin ("fiyat değişikliği aramaya en fazla 60 saniyede yansır") ve bunu ölçün. Senkronizasyonun tipik bozulma biçimlerini entegrasyon veri senkronizasyonu yazısında, göstergeye bağlamayı izlenebilirlik yazısında yazdık. Ayrıca ikinci sistem bellek ister, yedek ister, sürüm yükseltmesi ister ve dağıtım sırasında yeniden indeksleme penceresi ister.

Hibrit arama nerede işe yarar, nerede zarar verir

Anlamsal arama, kullanıcının kelimelerinin katalogdaki kelimelerle örtüşmediği durumlarda gerçekten fark yaratır: belirti sorguları, kullanım amacı sorguları, ürün dışı sorular. Anahtar kelime aramasıysa model kodlarında ve birebir eşleşmelerde tartışmasız daha iyidir. Hibrit yaklaşım ikisini paralel çalıştırıp sonuç listelerini birleştirir; sıralama birleştirmesi için karşılıklı sıra füzyonu en yaygın yöntem. Postgres'te kalmak isterseniz pgvector bir seçenek, Meilisearch ve Typesense de vektör aramayı destekliyor.

Maliyeti hafife alınıyor. Gömme üretmek için bir işlem hattı, içerik değiştiğinde yeniden gömme, model sürümünü sabitleme ve her sorguda ek gecikme gelir. Bir de anlamsal aramanın karakteristik hatası vardır: alakalı görünen ama yanlış olan sonucu kendinden emin biçimde üste koyar, 60 watt arayana 40 watt önerir. Kural basit: birebir kod eşleşmesi varsa anlamsal sonuç onu asla geçmesin. Bu arada yapay zekâ aramalarında görünürlük bambaşka bir konu, onu AEO ve GEO yazısında ayrıca ele aldık.

Bu haftaya sığan ilk adım

Aramayı günlüklemiyorsanız bu hafta yapacağınız tek iş o. Sorgu metni, sonuç sayısı, tıklanan sıra. İki hafta veri biriktikten sonra iki liste çıkarın: en çok aranan 200 sorgu ve hiç sonuç döndürmeyen sorgular. İkinci listeyi okuyunca sıranın kendiliğinden belirdiğini göreceksiniz, çoğu ekipte üst sıralar aynı çıkıyor: küçük harf ve şapka normalizasyonu, ürün dışı içeriğin indekste olmaması, sıfır sonuç ekranının çıkmaz sokak olması. Bunlar bir günlük işler ve motor değiştirmeyi gerektirmez.

Motor değişimini listenin sonuna koyun. Elinizde 100 sorgulu bir regresyon seti ve iki haftalık ölçüm yoksa yeni motorun daha iyi olduğunu kanıtlayamazsınız, yalnızca faturayı büyütmüş olursunuz. Kendi arama günlüğünüze bakıp hangi adımın karşılığının en büyük olduğunu belirlemekte yardım isterseniz, mevcut verinizle başlayıp somut bir sıra çıkarabiliriz.


Bu konuda yardıma mı ihtiyacınız var?

iletişime geçtüm yazılar