OpenSearch ve CJK ile Yazım Yanlışı Toleranslı Arama Özelliğini Nasıl Ekledim

Sonuç döndürmeyen sorgular izlenme süremizi baltalıyordu.

Bir yıl boyunca TopVideoHub, arama için SQLite FTS5 kullandı. Tam eşleşmelerde işe yarıyordu ancak kullanıcılar yazım yanlışı yaptığında başarısız oluyordu.

İnsanlar "demon slayer" yerine "demon slyer" diye aratıyordu. Japonca veya Korece başlıklara fazladan boşluklar ekliyorlardı. FTS5 tam tokenları eşleştirdiği için, tek bir yazım yanlışı sıfır sonuç demekti. Kullanıcılar tekrar arama yapmıyor, sadece uygulamadan ayrılıyordu.

Başlık aramalarımızı OpenSearch'e taşıdım. Çok dilli bir kitle için bu sorunu nasıl çözdüğümü aşağıda açıklıyorum.

Standart Fuzziness Sorunu

Çoğu eğitim rehberi, yazım yanlışlarını düzeltmek için "fuzziness" kullanmanızı söyler. Bu İngilizce için işe yarar ancak Çince, Japonca ve Korece (CJK) metinlerde başarısız olur.

  • Edit distance, CJK için kötüdür. CJK'da bir yazım yanlışı genellikle tamamen yanlış bir karakter kullanılması anlamına gelir.
  • Standart fuzziness, anlamsal çöpler oluşturur. "Fire" ile "water" kelimelerini, aralarında sadece bir edit farkı olduğu için eşleştirebilir.
  • Tokenization zordur. CJK dilleri kelimeler arasında boşluk kullanmaz.

Çözüm: Çoklu Alan Yaklaşımı

Tüm metinlere aynı şekilde davranmayı bıraktım. Üç farklı yöntemle indeksleme yapan tek bir mantıksal başlık alanı oluşturdum:

  • Latin ve Romaji: Fuzziness etkinleştirilmiş standart tokenization kullandım. Prefix length değerini 1 olarak ayarladım. Bu, "demon" kelimesinin "demn" ile eşleşmesini sağlarken "lemon" kelimesinin "demon" ile eşleşmemesini sağlar.
  • CJK Metni: Bir CJK bigram analizörü ve bir ICU normalizer kullandım. Fuzziness özelliğini KAPATTIM. Bunun yerine %70'lik bir minimum eşleşme eşiği (minimum match threshold) kullandım.
  • Autocomplete: Yazarken arama (search-as-you-type) sonuçlarını desteklemek için bir edge-ngram alanı kullandım.

Mimari ve Veri Güvenliği

SQLite'ı tek gerçeklik kaynağı (single source of truth) olarak tuttum. OpenSearch ise hızlı ve yeniden oluşturulabilir bir indeks görevi görüyor.

  • Güncellemeleri toplu paketler (bulk batches) halinde OpenSearch'e göndermek için PHP kullanıyorum.
  • İndeksleme işlemini asla bir kullanıcı isteği sırasında çalıştırmıyorum.
  • "Drift" (sapma) olup olmadığını kontrol etmek için bir Python betiği çalıştırıyorum. Bu, OpenSearch sayısının SQLite sayısıyla eşleşmesini sağlar.

Sonuçlar

Değişim muazzamdı:

  • Sonuç döndürmeyen sorgular %14'ten %3'ün altına düştü.
  • Kullanıcılar istediklerini anında bulabildikleri için arama oturumları uzadı.
  • Gecikme süresi (latency) 40ms civarında düşük kalmaya devam ediyor.

Çok dilli bir kitleye hizmet veriyorsanız şunu unutmayın: yazım yanlışı toleransı ve CJK eşleştirmesi iki farklı problemdir. İki farklı çözüme ihtiyacınız var.

Kaynak: https://dev.to/ahmet_gedik778845/how-i-added-typo-tolerant-video-title-search-with-opensearch-and-cjk-3e5d