- मौजूदा database का उपयोग करके बिना बाहरी service के चलने वाली search engine architecture को implement किया गया है, जिसमें tokenization, weight, और scoring पर फोकस है
- मुख्य विचार यह है कि सारे text को tokenize करके store किया जाए, और search के समय उसी तरीके से tokens को match करके relevance निकाली जाए
- Word, Prefix, N-Gram tokenizer को मिलाकर exact match, partial match, और typo handling — तीनों को संभाला जाता है, और हर tokenizer का अपना अलग weight होता है
- weight system और SQL-आधारित scoring algorithm के जरिए document length, token diversity, average quality आदि का संयुक्त मूल्यांकन किया जाता है
- scalability और transparency अधिक होने के कारण, नए tokenizer या document type जोड़ना, weight adjust करना, और scoring बदलना आसान है
खुद सर्च इंजन बनाने की वजह
- Elasticsearch या Algolia जैसी बाहरी services शक्तिशाली हैं, लेकिन उनके साथ जटिल API सीखने और infrastructure management का बोझ भी आता है
- जब सिर्फ मौजूदा database के साथ integrated, और debug करने में आसान search feature चाहिए हो, तब खुद बनाना उपयोगी होता है
- लक्ष्य है बिना बाहरी dependency के high-relevance results लौटाने वाला एक सरल search engine
मुख्य अवधारणा: tokenization और matching
- मूल सिद्धांत यह है कि सारे text को tokenize करके store किया जाए, और search के समय उसी तरीके से tokens बनाकर match किया जाए
- indexing चरण में content को token units में विभाजित करके weight के साथ store किया जाता है
- search चरण में query को भी उसी तरह tokenize करके matching tokens खोजे जाते हैं और score निकाला जाता है
- scoring चरण में stored weights का उपयोग करके relevance score तैयार किया जाता है
database schema design
- दो tables का उपयोग:
index_tokens और index_entries
index_tokens: unique tokens और tokenizer-वार weight store करता है
index_entries: token और document को जोड़ता है, और field, document, tokenizer weight को reflect करने वाला final score store करता है
- final weight calculation formula:
field_weight × tokenizer_weight × ceil(sqrt(token_length))
- index इस तरह सेट किए जाते हैं कि document lookup, token lookup, field-wise query, और weight filtering संभव हो
tokenization system
- WordTokenizer: शब्द-स्तर पर विभाजन, छोटे शब्द हटाना, exact match के लिए (weight 20)
- PrefixTokenizer: शब्द के prefix बनाना, autocomplete और partial match के लिए (weight 5)
- NGramsTokenizer: fixed-length character combinations बनाना, typo और partial match के लिए (weight 1)
- सभी tokenizer मिलकर lowercase conversion, special character removal, और whitespace normalization का common processing करते हैं
weight system
- field weight: title, body, keyword आदि की importance reflect करता है
- tokenizer weight: Word > Prefix > N-Gram क्रम
- document weight: ऊपर के दोनों factors और token length को मिलाकर निकाला जाता है
ceil(sqrt()) function लंबे tokens के प्रभाव को कम करता है, और जरूरत पड़ने पर इसे log या linear function से बदला जा सकता है
indexing service
- सिर्फ वे documents index किए जा सकते हैं जो
IndexableDocumentInterface implement करते हों
- document create/modify होने पर event listener या commands (
app:index-document, app:reindex-documents) के जरिए indexing की जाती है
- प्रक्रिया:
- पुराना index हटाकर नए tokens बनाए जाते हैं
- हर field पर सभी tokenizer चलाए जाते हैं
- token के मौजूद होने की जाँच के बाद उसे बनाया जाता है (
findOrCreateToken)
- calculated weight के साथ
index_entries में batch insert किया जाता है
- यह structure duplicate prevention, performance improvement, और update handling को ध्यान में रखता है
search service
- query को उन्हीं tokenizer से process किया जाता है ताकि indexing के समान token set मिले
- duplicate tokens हटाकर उन्हें length के अनुसार sort किया जाता है (लंबे token पहले), और अधिकतम 300 तक सीमित किया जाता है
- SQL query के जरिए token और document को join करके relevance score calculate और sort किया जाता है
- result
SearchResult(documentId, score) के रूप में लौटता है
scoring algorithm
- base score:
SUM(sd.weight)
- token diversity adjustment:
LOG(1 + COUNT(DISTINCT token_id))
- average weight adjustment:
LOG(1 + AVG(weight))
- document length penalty:
1 / (1 + LOG(1 + token_count))
- normalization: अधिकतम score से divide करके 0~1 range में adjust किया जाता है
- minimum token weight filter (
st2.weight >= ?) के जरिए बेकार low-weight matches हटाए जाते हैं
result processing
- search results document ID और score के रूप में लौटते हैं, और repository के जरिए उन्हें वास्तविक documents में बदला जाता है
FIELD() function का उपयोग करके search result order बनाए रखते हुए document lookup किया जाता है
system scalability
- नया tokenizer
TokenizerInterface implement करके जोड़ा जा सकता है
- नया document type
IndexableDocumentInterface implement करके register किया जा सकता है
- weight या scoring logic को सिर्फ SQL बदलकर adjust किया जा सकता है
निष्कर्ष
- यह architecture सरल है, लेकिन वास्तव में काम करने वाला search engine प्रदान करता है, और बाहरी infrastructure के बिना भी पर्याप्त performance देता है
- स्पष्ट logic, पूरा control, और आसान debugging इसकी ताकत हैं
- यह रेखांकित करता है कि जटिल systems से ज़्यादा मूल्यवान वह code हो सकता है जिसे आप खुद समझ और control कर सकें
1 टिप्पणियां
Hacker News राय
सर्च का बुनियादी आइडिया सरल है और यह एक दिलचस्प problem space है
लेकिन बड़े पैमाने के डेटा को संभालना और अस्पष्ट queries को प्रोसेस करना ही असली मुश्किल है
DBMS-आधारित approach छोटे websites के स्तर तक तो ठीक है, लेकिन English Wikipedia के पैमाने पर जल्दी ही इसकी सीमा सामने आ जाती है
शुरुआत के लिए SeIRP e-book एक अच्छा मुफ़्त resource है
स्पष्ट सही जवाब का न होना इसे खास तौर पर कठिन बनाता है
Google कभी-कभी ads को भी ‘सबसे relevant result’ की तरह दिखाता है, इसलिए Marginalia Search एक अच्छा contrast case है
जानना चाहता हूँ कि क्या आपने कभी TREC papers देखे हैं
search engines को ad revenue कमाने की कोशिश करने वाले adversarial players से लगातार लड़ना पड़ता है
quality metrics को लगातार बदलते रहना पड़ता है ताकि वे उनका दुरुपयोग न कर सकें — यह एक कभी न खत्म होने वाला cat-and-mouse game बन जाता है
अगर मानक 1 query पर 5 सेकंड और प्रति मिनट 12 queries का हो, तो लगभग कितने बड़े corpus में search किया जा सकता है, यह जानना है
उदाहरण के लिए, Gilligan’s Island के wiki article और fan blog में से कौन-सा “बेहतर” result है, यह तय करना कठिन है
इसमें rank manipulation या keyword stuffing भी जुड़ जाए, तो यह scalability की समस्या से कहीं अधिक जटिल चुनौती बन जाती है
search वाकई बहुत कठिन काम है
Apple, Microsoft, OpenAI जैसी संसाधन और तकनीकी क्षमता से भरपूर कंपनियों की भी search quality कमज़ोर है
यह सिर्फ तकनीकी समस्या नहीं है
search quality बेहतर करने के लिए ranking parameters को बारीकी से tune करना पड़ता है, लेकिन ऐसा काम sprint या Jira जैसी management systems में plan करना मुश्किल होता है
आखिरकार यह ऐसा क्षेत्र है जहाँ developers को trust और autonomy चाहिए
वे AI models पर अरबों खर्च करते हैं, लेकिन web app या search को secondary मानते हैं, इसलिए ऐसा नतीजा आता है
लगभग 10 साल पहले मैंने search engine design में PhD कर रहे एक सहकर्मी के साथ काम किया था
वह search और database integration के बारे में बहुत जुनून से बात करता था, और उससे मैंने बहुत कुछ सीखा
कभी Apache Solr और Lucene के अंदरूनी हिस्सों को गहराई से समझना चाहूँगा
पहले open source search solutions नहीं थे, इसलिए उन्हें खुद बनाना पड़ता था
उस अनुभव से मिला सबक यह था: “अपना search engine खुद मत बनाओ”
सालों तक बहुत से लोग इस समस्या पर लगे रहे हैं, और खुद बनाने पर आप बेअंत maintenance hell में फँस जाते हैं
“typo correction जोड़ दीजिए”, “अगले साल classification system भी डालते हैं” जैसी माँगें शुरू हों तो उसका अंत नहीं होता
मुझे पहले Virginia University के Professor David Evans का search engine बनाने वाला course बहुत पसंद आया था
एक “classical search engine” को खुद बनाना बहुत मज़ेदार project था
course link और YouTube playlist देख सकते हैं
जिन search engines का मैं अक्सर उपयोग करता हूँ, उनके 2~3 अक्षरों वाले acronyms या शब्दों को ignore करने से मुझे शिकायत है
“mp3” या “PHP” जैसे छोटे शब्द search करते समय अगर उन्हें हटा दिया जाए, तो यह सच में बहुत असुविधाजनक है
Toby Segaran की Programming Collective Intelligence पढ़कर मुझे search, recommendation, classifiers जैसी कई तरह की ideas से प्रेरणा मिली थी
यह एक दिलचस्प लेख था
यह सोचने पर मजबूर करता है कि लोकप्रिय search engines जिस tokenizer optimization का इस्तेमाल करते हैं, वह कितना उन्नत होगा
मैं सोच रहा हूँ कि यह system scalability के साथ कितना अच्छा काम करेगा
Elasticsearch recommended scale से आगे भी काफ़ी प्रभावशाली performance दिखाता है
एक साधारण text search engine बनाना मुश्किल नहीं है
लेकिन एक अच्छा search engine बनाना बिल्कुल अलग बात है
केवल BM25 जैसे algorithm को implement कर देना काफ़ी नहीं है
जिन कंपनियों को मैंने consult किया है, उनमें से ज़्यादातर ने अपनी खुद की solution से शुरुआत की, लेकिन अंत में Elasticsearch या Opensearch पर migrate कर गईं
अपनी implementation शुरू में सरल लगती है, लेकिन समय के साथ ranking problems और performance degradation के कारण जटिल हो जाती है
“धीमा है”, “अजीब results आते हैं” जैसे लक्षण बार-बार दिखते हैं
Elasticsearch 10 साल पहले से ही इन समस्याओं को हल करता आ रहा है, और अब तो यह और भी आगे बढ़ चुका है
लोग कहते हैं “इसे configure करना कठिन है”, लेकिन आजकल ज़्यादातर चीज़ें auto-configured होती हैं, और managed services भी बहुत हैं
कुछ मामलों में यह Postgres से भी आसान है
आखिरकार असली चीज़ index mapping optimization है
कुछ लोग कहते हैं “ऐसी advanced features की ज़रूरत नहीं”, लेकिन हक़ीक़त में search quality सीधे business survival से जुड़ी होती है
अगर आपको सच में ठीक-ठाक search चाहिए, तो अंत में यह जटिलता स्वीकार करनी ही पड़ती है
हाल में HN पर अक्सर ज़िक्र होने वाले SeekStorm जैसे उभरते विकल्प भी दिलचस्प लगते हैं, लेकिन अभी तक मैंने production में उसका वास्तविक उपयोग नहीं देखा है
खासकर dynamic mapping बंद करने और अनावश्यक fields की indexing रोकने वाली टिप उपयोगी लगी
मेरी जानकारी में यह Lucene से भी पुराना project है