28 puan yazan xguru 2024-08-26 | 2 yorum | WhatsApp'ta paylaş
  • Postgres içinde semantik, tam metin ve bulanık aramanın tamamını barındıran hibrit bir arama motoru kurulabilir
  • Arama birçok uygulamanın önemli bir parçasıdır, ancak bunu düzgün şekilde uygulamak kolay değildir. Özellikle RAG pipeline’larında arama kalitesi tüm sürecin başarısını belirleyebilir
  • Semantik arama trend olsa da, geleneksel sözcük tabanlı arama hâlâ aramanın omurgasıdır
  • Semantik teknikler sonuçları iyileştirebilir, ancak en iyi şekilde sağlam bir metin tabanlı arama temeli üzerinde çalışır

Postgres ile bir arama motoru uygulamak

  • Üç tekniği birleştirme:
    • tsvector ile tam metin arama
    • pgvector ile semantik arama
    • pg_trgm ile bulanık eşleştirme
  • Bu yaklaşım her durumda mutlak en iyisi olmayabilir, ancak ayrı bir arama servisi kurmaya çok iyi bir alternatiftir
  • Mevcut Postgres veritabanı içinde uygulanıp ölçeklenebilen sağlam bir başlangıç noktasıdır
  • Her şey için Postgres kullanmanızın nedeni: Her yerde sadece Postgres kullanın, PostgreSQL yeterlidir, Sadece Postgres kullanın

FTS ve semantik aramayı uygulamak

  • Supabase’te hibrit arama uygulamasına dair harika bir dokümantasyon bulunduğu için, bunu başlangıç noktası olarak kullanacağız
  • Rehberi izleyerek GIN index ile FTS uygulanıyor, pgvector (bi-encoder dense retrieval olarak da bilinir) ile de semantik arama kuruluyor
  • Kişisel deneyime göre 1536 boyutlu embedding seçmek çok daha iyi sonuçlar verebiliyor
  • Supabase fonksiyonları CTE ve sorgularla değiştiriliyor, parametrelerin önüne de $ ekleniyor
  • Burada sonuçları birleştirmek için RRF (Reciprocal Ranked Fusion) kullanılıyor
  • Bu yöntem, birden fazla listede üst sıralarda yer alan öğelerin nihai listede de üst sıralara çıkmasını sağlar
  • Ayrıca bazı listelerde üstte, diğerlerinde altta olan öğelerin nihai listede gereğinden fazla yükselmesini de engeller
  • Skoru paydada sıralamayı kullanarak hesaplamak, düşük sıralı kayıtları dezavantajlı duruma getirebilir
  • Dikkat çekici noktalar
    • $rrf_k: İlk sıradaki öğenin skorunun aşırı yükselmesini önlemek için (çünkü sıralamaya bölünür), paydada genellikle k sabiti eklenerek skor yumuşatılır
    • $_weight: Her yönteme ağırlık atanabilir. Bu, sonuçları ayarlarken çok kullanışlıdır

Bulanık aramayı uygulamak

  • Önceki yöntemler birçok sorunu çözebilir, ancak adlandırılmış varlıklarda yazım hatası varsa anında sorun çıkabilir
  • Semantik arama benzerliği yakalayarak bu sorunların bir kısmını azaltır, ancak isimler, kısaltmalar ve semantik olarak benzer olmayan diğer metinler için zorlanır
  • Bunu hafifletmek için bulanık aramaya izin veren pg_trgm eklentisi devreye alınır
    • Trigram ile çalışır. Trigram, kelimeleri 3 karakterlik dizilere ayırdığı için bulanık arama için kullanışlıdır
    • Böylece yazım hataları veya küçük varyasyonlar olsa bile benzer kelimeler eşleştirilebilir
    • Örneğin "hello" ve "helo" birçok trigramı paylaştığı için bulanık aramada daha kolay eşleşebilir
  • İstenen sütunlar için yeni bir index oluşturulup ardından genel arama sorgusuna eklenir
  • pg_trgm eklentisi, benzerliği pg_trgm.similarity_threshold değerinden (varsayılan 0.3) büyük olan metinleri filtrelemek için % operatörünü sunar
  • Bunun dışında da faydalı başka operatörler vardır

Tam metin aramayı ayarlamak

  • tsvector ağırlıklarını ayarlamak: gerçek bir belge yalnızca başlık değil, içerik de içerir
  • Birden fazla sütun olsa bile embedding sütunu tek tutulur
  • Kişisel olarak, birden fazla embedding tutmak yerine title ve body alanlarını aynı embedding içinde tutmanın performansta büyük fark yaratmadığını gördüm
  • Sonuçta title, gövdenin kısa bir ifadesi olmalıdır. Gerektiğinde bunu denemek iyi olur
  • title kısa ve anahtar kelime açısından zengin olma eğilimindeyken, body daha uzun olup daha fazla ayrıntı içerir
  • Bu nedenle tam metin arama sütunlarının birbirine göre nasıl ağırlıklandırılacağını ayarlamak gerekir
  • Belgedeki kelimenin konumuna veya önemine göre öncelik verilebilir
    • A-weight: en önemli (örn. başlık, header). Varsayılan 1.0
    • B-weight: önemli (örn. belgenin başlangıcı, özet). Varsayılan 0.4
    • C-weight: standart önem (örn. gövde metni). Varsayılan 0.2
    • D-weight: en az önemli (örn. dipnotlar, açıklamalar). Varsayılan 0.1
  • Belge yapısına ve uygulama gereksinimlerine göre ağırlıklar ayarlanarak alaka düzeyi ince ayarlanabilir
  • Başlığa daha fazla ağırlık verilmesinin nedeni
    • Başlık genellikle belgenin ana konusunu kısa ve öz biçimde ifade eder
    • Kullanıcılar arama yaparken önce başlıklara göz gezdirdiğinden, başlıktaki anahtar kelime eşleşmesi genellikle gövde metnindeki eşleşmeden daha çok kullanıcı niyetiyle ilişkilidir

Uzunluğa göre ayarlama

  • ts_rank_cd dokümantasyonunu okursanız bir normalizasyon parametresi olduğunu görebilirsiniz
    • Her iki sıralama fonksiyonu da belge uzunluğunun sıralamayı nasıl etkilemesi gerektiğini belirleyen tamsayı normalization seçeneğini kullanır. Bu tamsayı seçenek, birden fazla davranışı kontrol ettiği için bir bit mask’tir: | kullanarak bir veya daha fazla davranış belirtilebilir (örn. 2|4).

  • Bu çeşitli seçeneklerle şunlar yapılabilir
    • Belge uzunluğu yanlılığını ayarlamak
    • Farklı belge kümelerinde alaka dengesini kurmak
    • Tutarlı gösterim için sıralama sonuçlarını ayarlamak
  • Başlık için 0 (normalizasyon yok), gövde için 1 (log belge uzunluğu) ayarlamak iyi sonuç verebilir
  • Yine de kullanım senaryonuza en uygun seçeneği bulmak için farklı seçenekleri denemek faydalıdır

Cross-encoder ile yeniden sıralama

  • Birçok arama sistemi iki aşamadan oluşur
  • Yani önce bi-encoder ile ilk N sonuç bulunur, ardından cross-encoder bu sonuçları arama sorgusuyla karşılaştırarak yeniden sıralar
    • Bi-encoder: hızlı olduğu için çok sayıda belgeyi aramak için uygundur
    • Cross-encoder
      • Daha yavaştır ama performansı daha iyidir; bu yüzden bulunan sonuçları yeniden sıralamak için uygundur
      • Sorgu ve belgeyi birlikte işleyerek aralarındaki ilişkiyi daha incelikli biçimde anlamayı mümkün kılar
      • Bu da hesaplama süresi ve ölçeklenebilirlik pahasına daha iyi sıralama doğruluğu sağlar
  • Bunu yapmak için çeşitli araçlar vardır
  • En iyilerden biri Cohere’in Rerank aracı
  • Başka bir yol da OpenAI’nin GPT’sini kullanarak bunu kendiniz kurmak
  • Cross-encoder, sorgu ile belge arasındaki ilişkiyi daha iyi anlayabildiği için arama sonuçlarının doğruluğunu artırabilir
  • Ancak hesaplama maliyeti yüksek olduğundan ölçeklenebilirlik açısından sınırlamaları vardır
  • Bu nedenle, ilk arama için bi-encoder kullanıp cross-encoder’ı yalnızca bulunan az sayıdaki belgeye uygulayan iki aşamalı yaklaşım etkilidir

Ne zaman alternatif çözümlere bakılmalı

  • PostgreSQL birçok arama senaryosu için uygun bir seçimdir, ancak sınırsız değildir
  • BM25 gibi gelişmiş algoritmaların yokluğu, farklı belge uzunluklarını işlerken hissedilebilir
  • PostgreSQL’in tam metin araması TF-IDF’e dayandığı için çok uzun belgelerde ve büyük koleksiyonlardaki nadir terimlerde zorlanabilir
  • Alternatif çözümler aramadan önce mutlaka ölçüm yapılmalıdır. Buna değmeyebilir

Sonuç

  • Bu yazı, temel tam metin aramadan bulanık eşleştirme, semantik arama ve sonuç güçlendirme gibi gelişmiş tekniklere kadar pek çok konuyu ele alıyor
  • Postgres’in güçlü özelliklerinden yararlanarak, belirli gereksinimlere uygun güçlü ve esnek bir arama motoru oluşturulabilir
  • Postgres arama için akla gelen ilk araç olmayabilir, ama gerçekten çok ileri gidebilir
  • Harika bir arama deneyiminin anahtarı
    • Sürekli yineleme ve ince ayar
    • Ele alınan debug teknikleriyle arama performansını anlamak, kullanıcı geri bildirimi ve davranışına göre ağırlıklar ile parametreleri ayarlamaktan çekinmemek gerekir
  • PostgreSQL gelişmiş arama özelliklerinden yoksun olabilir, ancak çoğu durumda yeterince güçlü bir arama motoru kurmak mümkündür
  • Alternatif çözümlere yönelmeden önce önce Postgres’in sunduklarını sonuna kadar kullanıp performansı ölçmek iyi olur; yine de yetersiz kalırsa o zaman başka çözümler değerlendirilebilir

2 yorum

 
eajrezz 2024-08-27

Korece aramanın da iyi çalışıp çalışmadığını merak ediyorum.

 
xguru 2024-08-26

Bugünkü haftalık konu da Postgres'ti; görünen o ki yine Postgres. Popülerliğiyle doğru orantılı olarak gerçekten çok fazla yazı çıkıyor gibi haha.
BM25 için aşağıdakilere göz atın.

pg_bm25 - Postgres'te Elastic seviyesinde kalite sunan Full-Text arama eklentisi
ParadeDB - PostgreSQL for Search