Postgres’i bir arama motoru olarak kullanmak
(anyblockers.com)- 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:
tsvectorile tam metin aramapgvectorile semantik aramapg_trgmile 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_trgmeklentisi 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_trgmeklentisi, benzerliğipg_trgm.similarity_thresholddeğ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
tsvectorağı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
titlevebodyalanları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 titlekısa ve anahtar kelime açısından zengin olma eğilimindeyken,bodydaha 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
- A-weight: en önemli (örn. başlık, header). Varsayılan
- 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_cddokü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ı
normalizationseç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çin1(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
Korece aramanın da iyi çalışıp çalışmadığını merak ediyorum.
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