· kaynak dev.to (home feed)
ParadeDB pg_search 0.26, on terimli BM25 sorgularını 4,3 kat hızlandırıyor ancak tek terimli aramayı yavaşlatıyor
Bağımsız bir dev.to benchmark'ı, ParadeDB'nin pg_search 0.26.0'ın on terimli bir BM25 sorgusunu 129ms'den 29ms'ye düşürdüğünü, ancak tek terimli aramaların yeni fieldnorm depolama düzeninde yaklaşık beş kat daha yavaş çalıştığını ortaya koyuyor.

Bir depolama yeniden yazımı, özellik sürümü değil
ParadeDB, pg_search 0.26.0'ı 3 Ekim'de yayınladı ve changelog, bunu extension'ın BM25 skorlamasının dayandığı belge başına alan uzunluğu değerlerini depolama biçiminde bir değişiklik olarak tanımlıyor. Fieldnorm adı verilen bu sayılar daha önce paylaşımlı tek bir dizide tutuluyordu; 0.26'da ise her terimin postings listesinin içinde yer alıyor. dev.to'da yayımlanan uygulamalı bir benchmark bu yeniden yazımın ne kazandırdığını ve neye mal olduğunu ölçmeyi hedefledi ve cevabın iki yönde birden ilerlediğini buldu.
pg_search, Postgres'e bir BM25 tam metin indeks türü (USING bm25) ekleyen bir Postgres extension'ıdır; böylece ilgililik sırasına göre sıralanan arama, sıradan btree indekslerinin yanında Postgres içinde çalışabilir.
Nasıl test edildi
Yazar, paradedb/paradedb:0.25.11-pg17 ve 0.26.0-pg17 sürümlerini ayrı container'larda çalıştırdı, her birine aynı 3 milyon satırlık tabloyu yükledi, her ikisinde de sentetik bir title sütunu üzerinde varsayılan bir bm25 indeksi oluşturdu ve her zamanlamayı EXPLAIN (ANALYZE, BUFFERS) ile doğruladı. Title sütunu, yaklaşık 260 kelimelik bir kelime dağarcığından Zipf dağılımına göre seçildi; böylece bazı terimler satırların %84'ünde görünürken diğerleri yaklaşık %10'unda görünüyor.
Kazandığı yer
On terimi OR ile birleştiren ve BM25 skoruna göre en iyi on sonucu döndüren bir sorgu — ParadeDB'nin kendi benchmark'ının hedeflediği sıralı disjanksiyon biçimi — 0.25.11'de yaklaşık 129ms'den 0.26.0'da yaklaşık 29ms'ye düştü; bu 4,3 katlık iyileşme tek seferlik değil, tekrarlanan çalışmalarda da korunuyor.
Plan çıktısı kazanımın sebebini açıklıyor. dev.to analizine göre eski sürüm üç ayrı skorlanmış alt sorgu çalıştırıp bunları birleştirirken (planda Queries: 3 olarak görünüyor), yeni sürüm tek bir sorgu çalıştırıyor ve fieldnorm'lar, executor'ın üç kez ziyaret etmek zorunda kaldığı bir yapı yerine postings'in yanında yer alıyor.
Kaybettiği yer
En iyi on sonucu döndüren tek terimli bir sorgu tam tersini gösterdi: satırların %19'unda bulunan bir terimde, 0.25.11'de yaklaşık 1,4ms'ye karşılık 0.26.0'da yaklaşık 8ms; tutarlı biçimde yaklaşık beş kat daha yavaş. Satırların yaklaşık %10'unu kapsayan daha nadir bir terim de aynı örüntüyü daha küçük mutlak sayılarla gösterdi: 1,5-1,6ms'ye karşılık 4,8-5,7ms.
Buffer muhasebesi nedeni doğruluyor: 0.26.0'da 496 buffer erişimi, önceki sürümde ise 132; yeni erişimlerin 382'si özellikle field norm'lara atfediliyor. Alan uzunluğu verisini her terimin postings'inin yanında taşımak, yalnızca tek bir terim söz konusu olduğunda fayda olmadan maliyet ekliyor; on terim tek bir skorlanmış geçişe dönüştüğünde ise tam da meyvesini veren yerel özellik (locality) sağlıyor. Aynı tasarım kararı her iki sayıyı da üretiyor.
Dengenin tersine döndüğü yer
Yazar, kesişim noktasını her yapılandırma için üç çalışmanın en hızlısını kullanarak haritaladı: bir terim 1,34ms'ye karşılık 7,70ms, iki terim 8,10ms'ye karşılık 16,07ms, dört terim 20,40ms'ye karşılık 14,83ms ve on terim 127,5ms'ye karşılık 29,4ms. İki ile dört OR-terimi arasında bir yerde yeni sürüm kaybetmeyi bırakıp kazanmaya başlıyor ve bu noktanın ötesinde fark hızla açılıyor. Dört terimli bir AND sorgusu örneklem gürültüsü sınırları içinde kaldı (8,7-10,7ms'ye karşılık 9,5-11,4ms); bu da optimizasyonun disjanksiyonları hedeflediği, konjunksiyonları değil, ile tutarlı.
Disk maliyeti ve kaba kenarlar
İndeks neredeyse büyümedi: 100.917.248 bayta karşılık 101.138.432 bayt; yaklaşık 96MB'lık bir indekste yaklaşık 216 KiB ya da %0,2 — yani düzen, her terim için fieldnorm dizisinin naif bir kopyasını depolamıyor.
İki operasyonel tuhaflık ortaya çıktı. text_fields içindeki bilinmeyen anahtarlar sessizce kabul ediliyor — hem anlamsız bir seçenek adı hem de tahmini bir 'pnorms' bayrağı hatasız biçimde indeks oluşturdu — oysa hatalı JSON ve geçersiz bir tokenizer adı düzgün biçimde başarısız oluyor. Bu, yanlış yazılmış ya da güncelliğini yitirmiş bir seçenek adının sizi uyarmayacağı anlamına geliyor. Extension ayrıca bir tabloyu hâlâ tek bir pg_search indeksiyle sınırlıyor ve uzun süredir var olan key_field seçeneği artık 0.26.0 itibarıyla bir kullanımdan kaldırma uyarısı veren belgelenmiş bir no-op.
Yazarın değerlendirmesine göre en pratik ek, EXPLAIN (ANALYZE, BUFFERS) içindeki kategori başına yeni buffer dökümü; bu, canlı bir sistemde belirli bir sorgunun fieldnorm ek yükünü ödeyip ödemediğini ya da tek geçişli disjanksiyon yolundan yararlanıp yararlanmadığını görmenizi sağlıyor.
Neden önemli
0.26.0'ın net bir yükseltme olup olmadığı neredeyse tamamen sorgu biçimine bağlı. Geniş, çok terimli arama sorguları yapan uygulamalar — tipik arama kutusu deseni — büyük ve tekrarlanabilir bir hızlanma kazanıyor. Kısa sorgulara dayanan iş yükleri, örneğin tek anahtar kelime aramaları ya da otomatik tamamlama tarzı aramalar, ölçülen vakada kabaca beş kat olan gerçek ve tutarlı bir gerileme yaşıyor. Ekipler yükseltmeden önce kendi sorgu karışımını yeni buffer aracıyla profillemeden geçmeli ve alan seçenekleri doğrulamasına hataları yakalamak için güvenen herkes için bilinmeyen seçeneklerin sessizce kabul edilmesi dikkat çekilmeye değer.
- #postgres
- #full-text-search
- #benchmark
- #database
- #bm25