PostgreSQL फुल-टेक्स्ट सर्च: सही तरीके से करें तो तेज़ है (धीमा होने की गलतफ़हमी दूर)
(blog.vectorchord.ai)- PostgreSQL के built-in Full-Text Search(FTS) को अक्सर धीमा माना जाता है, लेकिन सही optimization करने पर यह बहुत तेज़ चलता है
- Neon के ब्लॉग में Rust-आधारित
pg_searchextension और built-in FTS की तुलना करके दावा किया गया कि बाद वाला धीमा है - लेकिन यह तुलना संभवतः ऐसी स्थिति में की गई थी जहाँ PostgreSQL FTS के लिए ज़रूरी बेसिक optimization steps शामिल नहीं थे
- यह लेख संख्याओं के साथ दिखाता है कि सिर्फ साधारण optimization लागू करके भी built-in FTS में 50x performance improvement मिल सकता है
बेंचमार्क सेटअप का अवलोकन
- 1 करोड़ log entries वाली table पर टेस्ट किया गया
CREATE TABLE benchmark_logs ( id SERIAL PRIMARY KEY, message TEXT, country VARCHAR(255), severity INTEGER, timestamp TIMESTAMP, metadata JSONB ); - समस्या वाली query संरचना:
SELECT country, COUNT(*) FROM benchmark_logs WHERE to_tsvector('english', message) @@ to_tsquery('english', 'research') GROUP BY country ORDER BY country;- query के अंदर
to_tsvector()चलाया जा रहा है → बहुत inefficent - GIN index होने पर भी उसका सही उपयोग नहीं होता
- query के अंदर
टेस्ट वातावरण (डिफ़ॉल्ट सेटिंग की पुनरावृत्ति)
- EC2 i7ie.xlarge instance, लोकल NVMe SSD का उपयोग
- 4 vCPUs, PostgreSQL 16(Docker) का उपयोग
- मुख्य PostgreSQL सेटिंग्स:
-c shared_buffers=8GB -c maintenance_work_mem=8GB -c max_parallel_workers=4 -c max_worker_processes=4 - parallel processing सीमा: max_parallel_workers_per_gather = 2 (Neon ने 8 का उपयोग किया)
performance गिरने का कारण 1: real-time tsvector calculation
- query के अंदर
to_tsvector()चलाने पर: - हर बार text parsing, morphological analysis आदि करना पड़ता है
- index का बिल्कुल उपयोग नहीं हो पाता
-
समाधान:
tsvectorcolumn पहले से बनाकर index करें- 1.
tsvectorcolumn जोड़ें
ALTER TABLE benchmark_logs ADD COLUMN message_tsvector tsvector;- 2. डेटा भरें
UPDATE benchmark_logs SET message_tsvector = to_tsvector('english', message); - 3. index बनाएँ (
fastupdateनिष्क्रिय)CREATE INDEX idx_gin_logs_message_tsvector ON benchmark_logs USING GIN (message_tsvector) WITH (fastupdate = off); - 4. query बदलें
SELECT country, COUNT(*) FROM benchmark_logs WHERE message_tsvector @@ to_tsquery('english', 'research') GROUP BY country ORDER BY country;
- 1.
performance गिरने का कारण 2: GIN index में fastupdate=on सेटिंग
fastupdate=onwrite performance के लिए अच्छा है, लेकिन search performance पर बुरा असर डालता है- read-only या search-केंद्रित dataset के लिए
fastupdate=offज़रूरी है - index छोटा और तेज़ हो जाता है, और pending list process करने की ज़रूरत नहीं रहती
-
optimized GIN index बनाने का तरीका
CREATE INDEX idx_gin_logs_message_tsvector ON benchmark_logs USING GIN (message_tsvector) WITH (fastupdate = off);
performance improvement: 50x से अधिक सुधार
- optimization से पहले: लगभग 41.3 सेकंड (41,301 ms)
- optimization के बाद: लगभग 0.88 सेकंड (877 ms)
- लगभग 50x performance improvement दिखा
- कम parallel processing वाले वातावरण में भी यह performance हासिल की जा सकती है
ts_rank performance वास्तव में धीमी हो सकती है
ts_rankयाts_rank_cdसभी results का मूल्यांकन करके sort करते हैं, इसलिए ये अपेक्षाकृत धीमे हो सकते हैं- खासकर जब results बहुत अधिक हों, तब CPU/IO पर बड़ा लोड पड़ता है
उन्नत ranking फीचर: VectorChord-BM25 extension
- जहाँ ranking accuracy और speed महत्वपूर्ण हों, वहाँ dedicated extension का उपयोग अधिक प्रभावी हो सकता है
- VectorChord-BM25 PostgreSQL के लिए एक extension है, जो BM25 algorithm आधारित ranking evaluation देता है
- ऐसी रिपोर्ट भी हैं कि यह Elasticsearch से 3x तेज़ है
VectorChord-BM25 के फायदे
- BM25 algorithm: TF-IDF से अधिक उन्नत search ranking algorithm
- dedicated index format: Block WeakAnd आदि के साथ high-speed search optimization
bm25vectortype उपलब्ध: tokenized representation को store करने के लिए- search accuracy और speed दोनों में सुधार
निष्कर्ष: PostgreSQL का built-in FTS भी काफ़ी तेज़ है
tsvectorcolumn और सही GIN index(fastupdate=off) का उपयोग करने पर built-in FTS से भी बहुत तेज़ search संभव है- performance comparison optimized baseline पर किया जाना चाहिए
- अगर advanced ranking फीचर चाहिए, तो VectorChord-BM25 जैसे extension tools पर विचार किया जा सकता है
- मुख्य संदेश: tool धीमा नहीं है, समस्या settings में हो सकती है
3 टिप्पणियां
इसी की बदौलत मैंने query tuning की।
Hacker News की राय तो डरावनी है... "एक करोड़? मज़ाक कर रहे हो?"
Hacker News राय
pg_search के मेंटेनर के रूप में, Postgres docs के अनुसार Neon/ParadeDB लेख और यहाँ इस्तेमाल की गई रणनीति दोनों वैध विकल्पों के रूप में पेश किए गए हैं
tsvector को real time में calculate करना एक बड़ी गलती है
मैं यह समझ नहीं पाता कि हर चीज़ को Postgres में डालने की प्रवृत्ति क्यों है
Postgres-native full text search implementations ज़्यादा देखने को मिल रहे हैं, यह देखकर खुशी है
execution plan न होने से यह समझना मुश्किल है कि क्या हो रहा है
कुछ साल पहले मैं native FTS का उपयोग करना चाहता था, लेकिन असफल रहा
मैंने pg_search और vchord_bm25 extension RPM/DEB को package किया है
मैंने कई teams को सीधे Elasticsearch या Meilisearch पर जाते देखा है
1 करोड़ records एक toy dataset है
2008 के आसपास मैंने पहली बार pg full text का उपयोग किया था