PostgreSQL फुल‑टेक्स्ट सर्च कई ऐप्स को कवर कर सकता है। एक साधारण निर्णय नियम, प्रारम्भिक क्वेरी और इंडेक्सिंग चेकलिस्ट से पता लगाएं कब आपको अलग सर्च इंजन जोड़ना चाहिए।

ts_rank (या ts_rank_cd) का उपयोग कर सकते हैं।\n\nभाषा कॉन्फ़िगरेशन मायने रखती है क्योंकि यह तय करती है कि Postgres शब्दों के साथ कैसे व्यवहार करे। सही कॉन्फ़िग के साथ “running” और “run” मैच कर सकते हैं (stemming), और सामान्य फिलर शब्द नजरअंदाज किए जा सकते हैं (stop words)। गलत कॉन्फ़िग के साथ सर्च टूटा हुआ महसूस हो सकता है क्योंकि सामान्य यूज़र शब्द अब इंडेक्स किए गए रूप से मैच नहीं करते।\n\nप्रीफिक्स मैचिंग वह फीचर है जिसकी लोग टाइपएड‑जैसी बर्ताव के लिए मांग करते हैं, जैसे “dev” से “developer” मैच होना। Postgres FTS में यह आमतौर पर प्रीफिक्स ऑपरेटर (term:*) से किया जाता है। यह अनुभव को बेहतर कर सकता है, पर अक्सर यह प्रति‑क्वेरी काम बढ़ा देता है, इसलिए इसे डिफ़ॉल्ट नहीं बल्कि वैकल्पिक उन्नयन समझें।\n\nPostgres यह नहीं बनने की कोशिश कर रहा: हर फीचर वाला एक पूरा सर्च प्लेटफ़ॉर्म। अगर आपको फज़ी स्पेलिंग करेक्शन, उन्नत ऑटोकम्पलीट, learning‑to‑rank, फील्ड‑वार जटिल analyzers, या कई नोड्स पर वितरित इंडेक्सिंग चाहिए, तो आप बिल्ट‑इन कम्फर्ट ज़ोन से बाहर हैं। फिर भी, कई ऐप्स के लिए PostgreSQL FTS वह अधिकांश चीज़ें देता है जो यूज़र्स उम्मीद करते हैं, बहुत कम मूविंग पार्ट्स के साथ।\n\n## एक शुरुआती क्वेरी जिसे आप कॉपी और अनुकूलित कर सकते हैं\n\nयहाँ एक छोटा, वास्तविक आकार है उन कंटेंट के लिए जिन्हें आप सर्च करना चाहते हैं:\n\nsql\n-- Minimal example table\nCREATE TABLE articles (\n id bigserial PRIMARY KEY,\n title text NOT NULL,\n body text NOT NULL,\n updated_at timestamptz NOT NULL DEFAULT now()\n);\n\n\nPostgreSQL FTS के लिए एक अच्छा बेसलाइन है: यूज़र ने जो टाइप किया उसे क्वेरी में बदलो, पहले रो को फ़िल्टर करो (जहाँ संभव हो), फिर बचे हुए मैचों को रैंक करो।\n\nsql\n-- $1 = user search text, $2 = limit, $3 = offset\nWITH q AS (\n SELECT websearch_to_tsquery('english', $1) AS query\n)\nSELECT\n a.id,\n a.title,\n a.updated_at,\n ts_rank_cd(\n setweight(to_tsvector('english', coalesce(a.title, '')), 'A') ||\n setweight(to_tsvector('english', coalesce(a.body, '')), 'B'),\n q.query\n ) AS rank\nFROM articles a\nCROSS JOIN q\nWHERE\n a.updated_at >= now() - interval '2 years' -- example safe filter\n AND (\n setweight(to_tsvector('english', coalesce(a.title, '')), 'A') ||\n setweight(to_tsvector('english', coalesce(a.body, '')), 'B')\n ) @@ q.query\nORDER BY rank DESC, a.updated_at DESC, a.id DESC\nLIMIT $2 OFFSET $3;\n\n\nकुछ विवरण जो बाद में समय बचाते हैं:\n\n- सस्ते फ़िल्टर को WHERE में पहले रखें (status, tenant_id, date ranges)। आप कम रो पर रैंक चलाएँगे, इसलिए यह तेज़ रहता है।\n- ORDER BY में हमेशा एक टाई‑ब्रेकर जोड़ें (जैसे updated_at, फिर id)। इससे पेजिनेशन स्थिर रहती है जब कई रिज़ल्ट्स की रैंक समान हो।\n- यूज़र इनपुट के लिए websearch_to_tsquery का उपयोग करें। यह कोट्स और सिंपल ऑपरेटर्स को ऐसे हैंडल करता है जैसा लोग उम्मीद करते हैं।\n\nएक बार यह बेसलाइन काम करने लगे, to_tsvector(...) एक्सप्रेशन को एक स्टोर किए हुए कॉलम में ले जाएँ। इससे हर क्वेरी पर यह फिर से न बने और इंडेक्सिंग सरल हो जाएगी।\n\n## इंडेक्सिंग सेटअप जो आमतौर पर फायदा देता है\n\nअधिकांश “PostgreSQL FTS धीमा है” कहानियाँ एक बात पर आती हैं: डेटाबेस हर क्वेरी पर सर्च डॉक्यूмент बना रहा है। इसे पहले ठीक करें — एक प्रीबिल्ट tsvector स्टोर करें और उस पर इंडेक्स बनाएं।\n\n### tsvector स्टोर करें: generated column या trigger?\n\nGenerated column सबसे सरल ऑप्शन है जब आपका सर्च डॉक्यूमेंट उसी रो के कॉलम्स से बनता है। यह स्वतः सही रहता है और अपडेट्स के दौरान भूलना मुश्किल है।\n\nजब डॉक्यूमेंट संबंधित टेबल्स पर निर्भर हो (उदाहरण के लिए, एक प्रोडक्ट रो को उसकी कैटेगरी नाम के साथ मिलाना), या जब कस्टम लॉजिक हो जिसे एक ही जनरेटेड एक्सप्रेशन में व्यक्त करना मुश्किल हो, तो trigger‑maintained tsvector उपयोग करें। ट्रिगर्स मूविंग पार्ट्स जोड़ते हैं, इसलिए उन्हें छोटा रखें और टेस्ट करें।\n\n### जो इंडेक्स आप लगभग हमेशा चाहेंगे\n\ntsvector कॉलम पर GIN इंडेक्स बनाएं। यह बेसलाइन है जो PostgreSQL FTS को सामान्य ऐप सर्च के लिए तुरंत सा महसूस करवाता है।\n\nकई ऐप्स के लिए काम करने वाला सेटअप:\n\n- tsvector को उसी टेबल में रखें जिसे आप सबसे ज़्यादा सर्च करते हैं।\n- उस tsvector पर GIN इंडेक्स जोड़ें।\n- सुनिश्चित करें कि आपका क्वेरी स्टोर किए हुए tsvector के खिलाफ @@ का उपयोग कर रहा है, न कि to_tsvector(...) को ऑन‑फ्लाई बनाकर।\n- बड़े बैकफिल के बाद प्लानर को नए इंडेक्स समझाने के लिए VACUUM (ANALYZE) पर विचार करें।\n\nवेक्टर को उसी टेबल में रखना आमतौर पर तेज़ और सरल होता है। अलग सर्च टेबल तभी समझ में आती है जब बेस टेबल बहुत write‑heavy हो, या जब आप एक संयुक्त डॉक्यूमेंट इंडेक्स कर रहे हों जो कई टेबल्स को फैला हुआ हो और आप उसे अपनी शेड्यूल पर अपडेट करना चाहते हों।\n\nPartial indexes मदद कर सकते हैं जब आप केवल सबसेट सर्च करते हैं, जैसे status = 'active', किसी एक tenant के लिए, या किसी विशेष भाषा के लिए। वे इंडेक्स साइज घटाते हैं और पढ़ने को तेज कर सकते हैं, पर तभी जब आपकी क्वेरियाँ हमेशा वही फ़िल्टर शामिल करें।\n\n## ओवर‑इंजीनियरिंग किए बिना स्वीकार्य रिलिवेंस पाना\n\nसरल और अनुमानयोग्य रिलिवेंस नियम रख कर आप PostgreSQL FTS से आश्चर्यजनक अच्छे नतीजे पा सकते हैं।\n\nसबसे आसान जीत फील्ड वेटिंग है: title में मैच body के मुकाबले अधिक गिनती होनी चाहिए। title को अधिक वज़न देकर एक संयुक्त tsvector बनाएं और फिर ts_rank या ts_rank_cd से रैंक करें।\n\nयदि आप चाहते हैं कि “ताज़ा” या “लोकप्रिय” आइटम ऊपर आएं, तो इसे सावधानी से करें। छोटा बूस्ट ठीक है, पर इसे टेक्स्ट रिलिवेंस को ओवरराइड नहीं करना चाहिए। एक प्रैक्टिकल पैटर्न है: पहले टेक्स्ट के अनुसार रैंक करें, फिर टाई‑ब्रेकर के रूप में recency इस्तेमाल करें, या एक कैप्ड बोनस जोड़ें ताकि एक निरर्थक नया आइटम पुराने परफेक्ट मैच को न हरा दे।\n\nSynonyms और phrase matching वहाँ अपेक्षाएँ अक्सर भिन्न होती हैं। Synonyms अपने‑आप नहीं मिलतीं; आपको thesaurus या कस्टम dictionary जोड़नी होगी, या खुद क्वेरी टर्म्स का विस्तार करना होगा (उदाहरण के लिए, “auth” को “authentication” के रूप में ट्रीट करना)। Phrase matching भी डिफ़ॉल्ट नहीं है: साधारण क्वेरियाँ शब्द कहीं भी मैच करती हैं, न कि “यह वही सटीक वाक्यांश”। यदि यूज़र्स कोटेड वाक्यांश या लंबे प्रश्न टाइप करते हैं, तो phraseto_tsquery या websearch_to_tsquery पर विचार करें।\n\nमिश्रित‑भाषा कंटेंट के लिए फैसला जरूरी है। अगर आप दस्तावेज़ के अनुसार भाषा जानते हैं, तो उसे स्टोर करें और सही कॉन्फ़िग के साथ tsvector जनरेट करें (English, Russian, आदि)। अगर भाषा अज्ञात है, तो सुरक्षित fallback simple कॉन्फ़िग के साथ इंडेक्स करना है (कोई stemming नहीं), या दो वेक्टर रखना: एक भाषा‑विशेष जब ज्ञात हो, और एक simple सभी के लिए।\n\nरिलिवेंस को मान्य करने के लिए सरल और ठोस रहें:\n\n- 10–20 असली यूज़र क्वेरियाँ इकट्ठा करें (या सपोर्ट चैट से)।\n- लिखें 1–3 रिज़ल्ट्स जो टॉप पर होने चाहिए।\n- हर ट्यूनिंग परिवर्तन के बाद उन्हें चलाएँ और नोट करें क्या बेहतर या बदतर हुआ।\n- जब यह आपके ऐप के लिए पर्याप्त लगे तो रोक दें।\n\nयह अक्सर PostgreSQL FTS के लिए काफी होता है जैसे “टेम्पलेट्स”, “डॉक्स”, या “प्रोजेक्ट्स” जैसे ऐप सर्च बॉक्स में।\n\n## आम गलतियाँ जो Postgres सर्च को खराब दिखाती हैं\n\nअधिकांश “PostgreSQL FTS धीमा या अप्रासंगिक है” कहानियाँ कुछ टालने योग्य गलतियों से आती हैं। इन्हें ठीक करना आमतौर पर नया सर्च सिस्टम जोड़ने से आसान होता है।\n\nएक आम जाल यह है कि tsvector को एक कंप्यूटेड वैल्यू समझना जो अपने आप सही रहती है। अगर आप tsvector को एक कॉलम में स्टोर करते हैं पर हर insert/update पर उसे अपडेट नहीं करते, तो रिज़ल्ट्स यादृच्छिक दिखेंगे क्योंकि इंडेक्स टेक्स्ट से मेल नहीं खाता। अगर आप क्वेरी में to_tsvector(...) ऑन‑फ्लाई बनाते हैं तो परिणाम सही हो सकते हैं पर धीमे होंगे और समर्पित इंडेक्स का लाभ खो जाएगा।\n\nदूसरा तरीका जिससे प्रदर्शन बिगड़ता है, वो है narrowing से पहले रैंकिंग करना। ts_rank उपयोगी है, पर सामान्यतः यह इंडएक्स से मिलान कर पाने के बाद चलना चाहिए। अगर आप लाखों रो पर रैंक कैल्कुलेट करते हैं (या पहले जॉइन करते हैं), तो एक तेज़ सर्च को टेबल स्कैन में बदल सकते हैं।\n\nलोग उम्मीद करते हैं कि “contains” सर्च LIKE '%term%' जैसा हो। लीडिंग वाइल्डकार्ड्स FTS के साथ अच्छा मेल नहीं खाते क्योंकि FTS शब्द (lexemes) पर आधारित है, न कि arbitrary substrings पर। अगर आपको substring सर्च चाहिए तो प्रॉडक्ट कोड्स या पार्टियल IDs के लिए अलग टूल उपयोग करें (जैसे ट्राईग्राम इंडेक्स)।\n\nपरफॉरमेंस समस्याएँ अक्सर मैचिंग नहीं बल्कि रिज़ल्ट हैंडलिंग से आती हैं। दो पैटर्न पर ध्यान दें:\n\n- बड़ा OFFSET पेजिनेशन, जो जितनी आगे आप पेज करें Postgres को उतने ही रो छोड़ने के लिए कहता है।\n- अनबाउंडेड रिज़ल्ट सेट्स, जहाँ क्वेरी दसियों हजार रो लौट सकती है।\n\nऑपरेशनल मुद्दे भी मायने रखते हैं। इंडेक्स बॉयल्ड हो सकता है कई अपडेट्स के बाद, और रीइंडेक्स महँगा हो सकता है अगर आप तब करें जब चीज़ें पहले से दर्दनाक हो। असली क्वेरी टाइम्स मापें (और EXPLAIN ANALYZE देखें) बदला करने से पहले और बाद में। बिना नंबरों के, PostgreSQL FTS “ठीक करने” का प्रयास करके दूसरी तरह से और खराब करना आसान है।\n\n## त्वरित चेकलिस्ट: क्वेरी और इंडेक्सिंग सैनीटी चेक\n\nPostgreSQL FTS को दोष देने से पहले ये चेक रन करें। अधिकांश समस्याएँ बुनियादी चीज़ों की कमी से आती हैं, फीचर से नहीं।\n\n### डेटा + इंडेक्स सैनीटी चेक\n\nएक असली tsvector बनाएं: इसे generated या maintained कॉलम में स्टोर करें (हर क्वेरी पर कंप्यूट न करें), सही भाषा कॉन्फ़िग उपयोग करें (english, simple, आदि), और अगर आप फील्ड्स मिला रहे हैं तो वेट्स लागू करें (title > subtitle > body)।\n\nजो आप इंडेक्स करते हैं उसे सामान्यीकृत करें: noisy फील्ड्स (IDs, boilerplate, नेविगेशन टेक्स्ट) को tsvector में न रखें, और बड़े ब्लॉब्स को ट्रिम करें अगर यूज़र्स उन्हें कभी खोजते ही नहीं।\n\nसही इंडेक्स बनाएं: tsvector कॉलम पर GIN इंडेक्स जोड़ें और पुष्टि करें कि यह EXPLAIN में उपयोग हो रहा है। अगर केवल एक सबसेट सर्चेबल है (जैसे status = 'published'), तो partial index साइज घटा सकता है और पढ़ने तेज कर सकता है।\n\nटेबल्स को स्वस्थ रखें: dead tuples इंडेक्स स्कैन को धीमा कर सकते हैं। नियमित vacuuming महत्वपूर्ण है, खासकर बार‑बार अपडेट होने वाली सामग्री पर।\n\nएक रीइंडेक्स योजना रखें: बड़े माईग्रेशन्स या बिआइन्डेक्स इंडेक्स को नियंत्रित विंडो की आवश्यकता हो सकती है।\n\nएक बार डेटा और इंडेक्स सही दिखे, तो क्वेरी शेप पर ध्यान दें। PostgreSQL FTS तब तेज़ है जब यह जल्दी candidate सेट को संकुचित कर सके।\n\n### क्वेरी + रनटाइम सैनीटी चेक\n\nपहले फ़िल्टर, फिर रैंक: सख्त फ़िल्टर (tenant, language, published, category) पहले लागू करें। हजारों रो पर रैंक करना जिन्हें बाद में आप डिस्कार्ड करेंगे, बेकार काम है।\n\nस्थिर ऑर्डरिंग का उपयोग करें: rank और फिर updated_at या id जैसे टाई‑ब्रेकर से order करें ताकि परिणाम रिफ्रेश के दौरान न कूदें।\n\n“क्वेरी सब कुछ करे” से बचें: अगर आपको फज़ी मैचिंग या टाइपो सहनशीलता चाहिए, तो उसे जानबूझकर लागू करें (और मापें)। अनजाने में sequential scans जबरदस्ती न कराएँ।\n\nअसली क्वेरियाँ टेस्ट करें: टॉप 20 सर्च इकट्ठा करें, हाथ से रिलिवेंस चेक करें, और छोटे अपेक्षित‑रिज़ल्ट्स की सूची रखें ताकि रिग्रेशन पकड़ी जा सके।\n\nस्लो पाथ्स पर नज़र रखें: slow queries लॉग करें, EXPLAIN (ANALYZE, BUFFERS) देखें, और इंडेक्स साइज और कैश हिट रेट मॉनिटर करें ताकि आप बढ़ोतरी के व्यवहार बदलने पर ध्यान दे सकें।\n\n## उदाहरण परिदृश्य: बेसिक साइट सर्च से बढ़ती ज़रूरतें तक\n\nएक SaaS हेल्प सेंटर शुरुआत के लिए अच्छा है क्योंकि लक्ष्य सरल है: लोगों को वह आर्टिकल मिल जाए जो उनके प्रश्न का उत्तर देता है। आपके पास कुछ हजार आर्टिकल्स हैं, हर एक के साथ title, short summary, और body टेक्स्ट। अधिकांश विज़िटर 2–5 शब्द टाइप करते हैं जैसे “reset password” या “billing invoice”。\n\nPostgreSQL FTS के साथ यह आश्चर्यजनक रूप से तेज़ी से पूरा हो सकता है। आप combined fields के लिए tsvector स्टोर करते हैं, GIN इंडेक्स जोड़ते हैं, और रिलिवेंस के अनुसार रैंक करते हैं। सफलता का मतलब: परिणाम 100 ms से कम में आते हैं, टॉप 3 आम तौर पर सही होते हैं, और आपको सिस्टम की निगरानी में समय नहीं देना पड़ता।\n\nफिर प्रोडक्ट बढ़ता है। सपोर्ट चाहता है कि फ़िल्टर product area, platform (web, iOS, Android), और plan (free, pro, business) से हो सकें। डॉक राइटर्स synonyms, “did you mean”, और बेहतर टाइपो हैंडलिंग चाहते हैं। मार्केटिंग टॉप सर्चेज़ के एनालिटिक्स चाहती है जहाँ 0 रिज़ल्ट्स दिखते हैं। ट्रैफ़िक बढ़ता है और सर्च सबसे व्यस्त एंडपॉइंट बन जाती है।\n\nये संकेत हैं कि समर्पित सर्च इंजन जोड़ना लागत के काबिल हो सकता है:\n\n- आप उसी पेज पर कई फ़िल्टर और फैसेट्स चाहते हैं साथ में फुल‑टेक्स्ट सर्च के।\n- आपको फज़ी मैचिंग, टाइपो सहनशीलता, या ऑटोकम्पलीट पहले‑क्लास चाहिए।\n- आपको सर्च एनालिटिक्स और रिलिवेंस के लिए फीडबैक लूप चाहिए।\n- सर्च ट्रैफ़िक इतना बड़ा है कि उसे प्राथमिक DB से अलग करना मायने रखता है।\n\nएक व्यावहारिक माइग्रेशन पथ यह है कि Postgres को सोर्स‑ऑफ‑ट्रूथ रखें, भले ही आप सर्च इंजन जोड़ दें। पहले सर्च क्वेरियों और नो‑रिज़ल्ट केस लॉग करें, फिर एक असिंक्रोनस सिंक जॉब चलाकर केवल सर्चेबल फील्ड्स को नए इंडेक्स में कॉपी करें। कुछ समय दोनों को समानांतर चलाएँ और धीरे‑धीरे स्विच करें, बजाय इसके कि सब कुछ एक दिन में बदल दें।\n\n## अगले कदम: एक बेसलाइन शिप करें, मापें, फिर निर्णय लें\n\nअगर आपकी सर्च ज़्यादातर “इन शब्दों वाले डॉक्यूमेंट ढूँढो” है और आपका डेटासेट बहुत बड़ा नहीं है, तो PostgreSQL FTS आमतौर पर काफी है। वहां से शुरू करें, काम कराएँ, और तभी समर्पित इंजन जोड़ें जब आप गायब फीचर या स्केलिंग दर्द का नाम दे सकें।\n\nएक सारांश जो हाथ में रखना चाहिए:\n\n- जब आप tsvector स्टोर कर सकते हैं, GIN इंडेक्स जोड़ सकते हैं, और आपकी रैंकिंग ज़रूरी से बेसिक हो, तब Postgres FTS का उपयोग करें।\n- एक starter क्वेरी और एक इंडेक्स सेटअप शिप करें, फिर असली लेटेंसी और “क्या लोग इसे ढूँढ पा रहे हैं?” मापें।\n- रिलिवेंस को छोटे, स्पष्ट बदलावों से ट्यून करें (weights, language config, query parsing), बड़े री‑राइट से नहीं।\n- केवल तब सर्च इंजन प्लान करें जब स्पष्ट गैप हों (autocomplete, मजबूत टाइपो सहनशीलता, फैसिटिंग) या विकास के संकेत (साइज़, लोड)।\n\nएक व्यावहारिक अगला कदम: पहले सेक्शन्स के starter क्वेरी और इंडेक्स को लागू करें, फिर एक सप्ताह के लिए कुछ सरल मीट्रिक्स लॉग करें। p95 क्वेरी समय, स्लो क्वेरियाँ, और एक मोटा सफलता संकेत जैसे “search → click → तुरंत बाउंस नहीं” ट्रैक करें (यहां तक कि एक बेसिक इवेंट काउंटर भी मदद करेगा)। आप जल्दी देख लेंगे कि क्या आपको बेहतर रैंकिंग चाहिए या बस बेहतर UX (फ़िल्टर, हाइलाइटिंग, बेहतर स्निपेट्स)।\n\nजब इनमें से कोई वास्तविक आवश्यकता बन जाए (न कि सिर्फ़ अच्छा‑हो), तब समर्पित सर्च इंजन की योजना बनाना शुरू करें: हर‑की‑की‑कीबोर्ड‑स्ट्रीक पर तत्काल सर्च, मजबूत टाइपो टोलरेंस और स्पेल करेक्शन, बहुत सारे फील्ड्स पर तेज़ फैसिटिंग और काउंट्स, उन्नत रिलिवेंस टूलिंग (synonym sets, learning‑to‑rank), या सतत उच्च लोड और बड़े इंडेक्स जिन्हें तेज रखना कठिन हो।\n\nअगर आप ऐप साइड पर तेजी से आगे बढ़ना चाहते हैं, तो Koder.ai (koder.ai) चैट के जरिए सर्च UI और API प्रोटोटाइप करने का एक उपयोगी तरीका हो सकता है; फिर स्नैपशॉट और रोलबैक के साथ सुरक्षित रूप से इटरेट करते हुए मापें कि यूज़र्स वाकई क्या करते हैं।PostgreSQL फुल‑टेक्स्ट सर्च “काफी” तब होता है जब आप एक साथ ये तीन चीज़ें पूरा कर पाते हैं:\n\n- प्रासंगिक परिणाम: स्पष्ट मैच टॉप पर दिखते हैं।\n- तेज़ उत्तर: सामान्य लोड पर रिज़ल्ट्स जल्दी आते हैं।\n- कम ऑपरेशनल ओवरहेड: आप एक अलग सिस्टम या सिंक पाइपलाइन नहीं चला रहे हैं।\n\nअगर आप ये tsvector + GIN इंडेक्स के साथ पूरा कर लेते हैं, तो आप आमतौर पर अच्छी स्थिति में रहते हैं।
पहले डिफ़ॉल्ट रूप से PostgreSQL फुल‑टेक्स्ट सर्च से शुरू करें। यह तेज़ी से शिप होता है, आपका डेटा और सर्च एक ही जगह रखते हैं, और अलग इंडेक्सिंग पाइपलाइन बनाने और मेंटेन करने से बचते हैं।\n\nजब किसी स्पष्ट आवश्यकता के कारण Postgres अच्छा प्रदर्शन नहीं दे पाता — जैसे उच्च‑गुणवत्ता की टाइपो सहनशीलता, समृद्ध ऑटोकम्पलीट, भारी फैसिटिंग, या सर्च लोड जो आपके मुख्य DB से संसाधन छीनता है — तब समर्पित इंजन पर जाएँ।
साधारण नियम: यदि आप इन तीन चेकों में पास होते हैं तो Postgres में रहें, वरना समर्पित सर्च इंजन पर विचार करें:\n\n1) रिलिवेंस की ज़रूरतें: “पर्याप्त” रैंकिंग स्वीकार्य है?\n2) लॉड + लेटेंसी: क्या सर्च आपके प्राइमरी DB को ओवरवhelम कर रहा है?\n3) जटिलता: क्या आप सिर्फ़ कुछ टेक्स्ट फ़ील्ड खोज रहे हैं और कुछ फ़िल्टर हैं?\n\nयदि आप इनमें किसी एक में बहुत खराब फेल होते हैं (खासकर टाइपो/ऑटोकम्पलीट या भारी सर्च ट्रैफ़िक), तो समर्पित इंजन सोचें।
Postgres FTS तब अच्छा मैच है जब आपकी खोज ज़्यादातर “सही रिकॉर्ड ढूँढो” तरह की हो: कुछ फ़ील्ड जैसे title/body/notes पर, और साधारण फ़िल्टर (tenant, status, category) हों।\n\nयह हेल्प सेंटर्स, इंटरनल डॉक, टिकट्स, ब्लॉग/आर्टिकल सर्च और SaaS डैशबोर्ड्स के लिए बहुत उपयुक्त है जहाँ लोग प्रोजेक्ट नाम और नोट्स से खोजते हैं।
एक अच्छा बेसलाइन क्वेरी आमतौर पर:\n\n- यूज़र इनपुट को websearch_to_tsquery से पार्स करता है।\n- सस्ते कंस्ट्रेंट्स पहले फ़िल्टर करता है (tenant/status/date)।\n- स्टोर किए गए tsvector पर @@ से मैच करता है।\n- ts_rank/ts_rank_cd और एक स्थिर टाई‑ब्रेकर जैसे updated_at, id के साथ ऑर्डर करता है।\n\nयह परिणामों को प्रासंगिक, तेज़ और पेजिनेशन के लिए स्थिर रखता है।
एक प्रीबिल्ट tsvector स्टोर करें और उस पर GIN इंडेक्स बनाएं। इससे हर रिक्वेस्ट पर to_tsvector(...) फिर से न बनाना पड़ेगा।\n\nप्रैक्टिकल सेटअप:\n\n- सर्चेबल tsvector को उसी टेबल में रखें जिसे आप क्वेरी करते हैं।\n- उस कॉलम पर GIN इंडेक्स बनाएं।\n- सुनिश्चित करें कि आपका क्वेरी tsvector_column @@ tsquery का उपयोग करता है।\n\nयह सबसे सामान्य फ़िक्स है जब सर्च धीमा लगती है।
जब सर्च डॉक्यूमेंट उसी रो के कॉलम्स से बने हों तो generated column सबसे सरल विकल्प है — यह स्वतः सही रहता है और अपडेट पर भूलना मुश्किल है।\n\nजब डॉक्यूमेंट संबंधित तालिकाओं पर निर्भर हो (जैसे प्रोडक्ट के साथ उसकी कैटेगरी नाम जोड़ना) या कस्टम लॉजिक हो जिसे एक सिंगल एक्सप्रेशन में बताना मुश्किल हो, तो trigger‑maintained tsvector उपयोग करें। ट्रिगर अधिक मूविंग पार्ट जोड़ते हैं, इसलिए उन्हें छोटा रखें और अच्छे से टेस्ट करें।
सरल और अनुमानयोग्य रिलिवेंस पाने के लिए:\n\n- फील्ड वेटिंग: title के मैच body की तुलना में अधिक महत्व रखें।\n- बूस्ट्स छोटे रखें: freshness या popularity का छोटा बोनस ठीक है, पर यह टेक्स्ट रिलिवेंस को ओवरराइड न करे।\n- सही भाषा कॉन्फ़िग: stemming और stop words “run/running” तरह की मैचिंग के लिए मायने रखते हैं।\n\nफिर इन्हें असली यूज़र क्वैरियों के छोटे सेट पर परखें।
Postgres FTS वर्ड‑आधारित है, substring‑आधारित नहीं। इसलिए यह LIKE '%term%' जैसा व्यवहार नहीं देता।\n\nयदि आपको substring खोज चाहिए (IDs, कोड, फ्रैगमेंट), तो आमतौर पर ट्राईग्राम इंडेक्स जैसी अलग टेक्निक उपयोग करें, बजाय यह उम्मीद करने के कि FTS वह काम करेगा जो वह डिज़ाइन नहीं किया गया है।
सिर्फ़ ऐसे संकेत जिनसे आप Postgres FTS से आगे बढ़ना चाहेंगे:\n\n- आपको मज़बूत टाइपो सहनशीलता, स्केल पर synonyms या समृद्ध ऑटोकम्पलीट चाहिए।\n- आपको तेज़ काउंट्स के साथ बहुत सारे facets/aggregations चाहिए।\n- सर्च ट्रैफ़िक इतना ज़्यादा है कि वह आपके प्राइमरी DB को स्ट्रेस कर रहा है।\n- आपको उन्नत रिलिवेंस टूलिंग चाहिए (फीडबैक लूप्स, learning‑to‑rank)।\n\nप्रैक्टिकल पथ यह है कि Postgres को सोर्स‑ऑफ‑ट्रूथ रखें और जब आवश्यकता स्पष्ट हो तब असिंक्रोनस इंडेक्सिंग जोड़ें।