सर्च सर्विस आर्किटेक्चर: वाल्की के साथ स्टैंडअलोन फ्लास्क एप्लिकेशन
यह लेख बताता है कि हमारी सर्च सर्विस एक अलग सर्वर पर एक स्टैंडअलोन फ्लास्क एप्लिकेशन के रूप में कैसे चलती है, जो उच्च-प्रदर्शन वेक्टर खोज, कैशिंग और ऑटोकम्प्लीट के लिए वाल्की (रेडिस फोर्क) का उपयोग करती है।
समस्या: खोज प्रदर्शन और स्केलेबिलिटी
खोज ऑपरेशन कम्प्यूटेशनल रूप से महंगे हैं:
-
फ़िल्टर निष्कर्षण: प्रत्येक क्वेरी के खिलाफ 2,500+ वाक्यांशों का मिलान करना
-
संबंधित खोजें: 65K क्वेरीज़ में समानता की गणना करना
-
ऑटोकम्प्लीट: 65K क्वेरीज़ पर प्रीफ़िक्स मिलान
-
उत्पाद फ़िल्टरिंग: कई मानदंडों द्वारा 5K+ उत्पादों को फ़िल्टर करना
मुख्य वेब सर्वर पर इन ऑपरेशनों को चलाने से होता है:
-
धीमा पेज लोड: खोज अन्य अनुरोधों को ब्लॉक करती है
-
मेमोरी दबाव: एम्बेडिंग्स एक विशाल मेमोरी फुटप्रिंट के लिए जिम्मेदार हैं
-
सीपीयू प्रतिस्पर्धा: समानता गणना सीपीयू-गहन है
-
स्केलिंग कठिनाई: खोज को स्वतंत्र रूप से स्केल नहीं कर सकते
हमें एक समर्पित खोज सेवा की आवश्यकता है जो स्वतंत्र रूप से स्केल कर सके।
समाधान: स्टैंडअलोन खोज सेवा
हम एक समर्पित सर्वर पर एक अलग फ्लास्क एप्लिकेशन चलाते हैं:
मुख्य वेब सर्वर
↓ HTTP API कॉल
खोज सेवा
↓ वाल्की क्वेरीज़
वाल्की सर्वर
यह आर्किटेक्चर प्रदान करता है:
-
स्वतंत्र स्केलिंग: मुख्य वेब सर्वर को प्रभावित किए बिना खोज सेवा को स्केल करें
-
संसाधन अलगाव: खोज ऑपरेशन मुख्य वेब सर्वर को प्रभावित नहीं करते
-
कैशिंग: वाल्की दोहराई गई क्वेरीज़ के लिए परिणाम कैश करती है
-
उच्च उपलब्धता: खोज सेवा मुख्य वेब सर्वर को प्रभावित किए बिना रीस्टार्ट कर सकती है
खोज सेवा घटक
1. फ़िल्टर निष्कर्षण API
-
एंडपॉइंट:
/api/extract_filters -
उद्देश्य: प्राकृतिक भाषा क्वेरीज़ से संरचित फ़िल्टर निकालना
-
उदाहरण:
GET /api/extract_filters?q=mini+pc+16gb+ram
प्रतिक्रिया:
{
"Form Factor": "Mini PC",
"Main Memory": "16"
}
कार्यान्वयन:
-
वाल्की या JSON से वाक्यांश-से-फ़िल्टर मैपिंग लोड करें
-
वर्ड बाउंडरी रेजेक्स का उपयोग करके वाक्यांशों का मिलान करें
-
संरचित फ़िल्टर लौटाएं
कैशिंग: वाक्यांश मैपिंग वाल्की में कैश की गई (30-दिन TTL)
2. संबंधित खोजें API
-
एंडपॉइंट:
/api/related -
उद्देश्य: वेक्टर खोज का उपयोग करके अर्थपूर्ण रूप से समान क्वेरीज़ ढूंढना
-
उदाहरण:
POST /api/related
{
"query": "mini pc",
"limit": 10
}
प्रतिक्रिया:
{
"related": [
{"query": "small computer", "similarity": 0.92},
{"query": "compact desktop", "similarity": 0.89},
{"query": "mini pc 8gb", "similarity": 0.87}
]
}
कार्यान्वयन:
-
all-mpnet-base-v2 का उपयोग करके क्वेरी को एम्बेड करें
-
निकटतम पड़ोसियों के लिए वाल्की रेडिसर्च क्वेरी करें
-
समानता के अनुसार क्रमबद्ध शीर्ष N परिणाम लौटाएं
कैशिंग: परिणाम वाल्की में कैश किए गए (7-दिन TTL)
3. ऑटोकम्प्लीट API
-
एंडपॉइंट:
/api/autocomplete -
उद्देश्य: उपयोगकर्ता के टाइप करते ही क्वेरीज़ सुझाना
-
उदाहरण:
GET /api/autocomplete?q=mini+p&limit=5
प्रतिक्रिया:
{
"suggestions": [
"mini pc",
"mini pc 16gb",
"mini pc 8gb ram",
"mini pc fanless",
"mini pc windows 11"
]
}
कार्यान्वयन:
-
प्रीफ़िक्स मिलान के साथ वाल्की रेडिसर्च क्वेरी करें
-
लोकप्रियता (इम्प्रेशन + क्लिक स्कोर) के अनुसार रैंक करें
-
शीर्ष N सुझाव लौटाएं
कैशिंग: ऑटोकम्प्लीट इंडेक्स वाल्की में (दैनिक अपडेटेड)
4. लोकप्रिय क्वेरीज़ API
-
एंडपॉइंट:
/api/popular -
उद्देश्य: सबसे लोकप्रिय क्वेरीज़ प्राप्त करना
-
उदाहरण:
GET /api/popular?limit=10
प्रतिक्रिया:
{
"queries": [
"mini pc",
"thin client",
"industrial pc",
"all in one pc"
]
}
कार्यान्वयन:
-
वाल्की या JSON से क्वेरीज़ लोड करें
-
ट्रैफ़िक स्कोर (इम्प्रेशन + क्लिक) के अनुसार क्रमबद्ध करें
-
शीर्ष N क्वेरीज़ लौटाएं
कैशिंग: लोकप्रिय क्वेरीज़ वाल्की में कैश की गईं (30-दिन TTL)
वाल्की एकीकरण
वाल्की एक रेडिस फोर्क है जो प्रदान करती है:
-
वेक्टर खोज: समानता खोज के लिए रेडिसर्च मॉड्यूल
-
कैशिंग: तेज़ इन-मेमोरी की-वैल्यू स्टोर
-
ऑटोकम्प्लीट: सॉर्टेड सेट्स के साथ प्रीफ़िक्स मिलान
-
स्थायित्व: स्थायित्व के लिए AOF (Append-Only File)
रेडिसर्च के साथ वेक्टर खोज
हम वेक्टर समानता खोज के लिए वाल्की के रेडिसर्च मॉड्यूल का उपयोग करते हैं:
इंडेक्स निर्माण:
client.ft("queries_idx").create_index([
VectorField("embedding", "FLAT", {
"TYPE": "FLOAT32",
"DIM": 768,
"DISTANCE_METRIC": "COSINE"
}),
TextField("query"),
NumericField("score")
])
वेक्टर खोज:
query_embedding = model.encode(query)
results = client.ft("queries_idx").search(
Query("*=>[KNN 10 @embedding $vec AS score]")
.sort_by("score")
.return_fields("query", "score")
.dialect(2),
query_params={"vec": query_embedding.tobytes()}
)
यह कोसाइन समानता द्वारा 10 निकटतम पड़ोसियों को लौटाता है।
कैशिंग रणनीति
हम वाल्की में कई डेटा प्रकार कैश करते हैं:
वाक्यांश मैपिंग (30-दिन TTL):
client.setex(
"seo:phrase_mappings",
30 * 24 * 3600,
json.dumps(phrase_mappings)
)
संबंधित खोजें (7-दिन TTL):
cache_key = f"related:{query_hash}"
client.setex(cache_key, 7 * 24 * 3600, json.dumps(results))
लोकप्रिय क्वेरीज़ (30-दिन TTL):
client.setex(
"seo:popular_queries",
30 * 24 * 3600,
json.dumps(popular_queries)
)
ऑटोकम्प्लीट इंडेक्स (दैनिक अपडेटेड):
for query, score in queries:
client.zadd("autocomplete:mini", {query: score})
सॉर्टेड सेट्स के साथ ऑटोकम्प्लीट
हम ऑटोकम्प्लीट के लिए वाल्की सॉर्टेड सेट्स का उपयोग करते हैं:
इंडेक्स संरचना:
autocomplete:m → ["mini pc": 5000, "mini computer": 3000]
autocomplete:mi → ["mini pc": 5000, "mini computer": 3000]
autocomplete:min → ["mini pc": 5000, "mini computer": 3000]
autocomplete:mini → ["mini pc": 5000, "mini computer": 3000]
प्रीफ़िक्स लुकअप:
prefix = "mini"
results = client.zrevrange(f"autocomplete:{prefix}", 0, 9, withscores=True)
यह "mini" से शुरू होने वाली शीर्ष 10 क्वेरीज़, स्कोर के अनुसार क्रमबद्ध, लौटाता है।
API संचार
मुख्य वेब सर्वर HTTP के माध्यम से खोज सेवा को कॉल करता है:
फ़िल्टर निष्कर्षण
from app.shared.filter_service import extract_filters_from_query
filters = extract_filters_from_query("mini pc 16gb ram")
# आंतरिक रूप से कॉल करता है: GET SEARCH_SERVICE_URL/api/extract_filters?q=...
संबंधित खोजें
import requests
response = requests.post(
"SEARCH_SERVICE_URL/api/related",
json={"query": "mini pc", "limit": 10},
timeout=2
)
related = response.json()["related"]
ऑटोकम्प्लीट
response = requests.get(
"SEARCH_SERVICE_URL/api/autocomplete",
params={"q": "mini p", "limit": 5},
timeout=1
)
suggestions = response.json()["suggestions"]
त्रुटि हैंडलिंग और फॉलबैक
मुख्य वेब सर्वर खोज सेवा विफलताओं को सहजता से संभालता है:
try:
filters = extract_filters_from_query(query)
except Exception as e:
logger.error(f"Search service failed: {e}")
filters = {} # फॉलबैक खाली फ़िल्टर पर
यह सुनिश्चित करता है कि खोज सेवा डाउन होने पर भी मुख्य वेब सर्वर कार्य करता रहे।
### नेटवर्क कॉन्फ़िगरेशन
सभी सर्वर एक निजी नेटवर्क पर हैं:
- **मुख्य वेब सर्वर**: खोज सेवा और वाल्की तक पहुंच सकता है
- **खोज सेवा**: वाल्की तक पहुंच सकती है
- **वाल्की**: केवल मुख्य वेब सर्वर और खोज सेवा से पहुंच योग्य
खोज सेवा या वाल्की तक कोई बाहरी पहुंच नहीं।
## SEO पाइपलाइन के साथ एकीकरण
खोज सेवा SEO पाइपलाइन के साथ एकीकृत होती है:
### चरण 11: वाल्की में माइग्रेट करें
SEO पाइपलाइन डेटा को वाल्की में लोड करती है:
```python
# क्वेरी एम्बेडिंग्स लोड करें
for query, embedding in zip(queries, embeddings):
client.hset(f"query:{query_hash}", mapping={
"query": query,
"embedding": embedding.tobytes(),
"score": score
})
# रेडिसर्च इंडेक्स बनाएं
client.ft("queries_idx").create_index([...])
विवरण के लिए वाल्की माइग्रेशन देखें।
क्वेरी लॉगिंग
खोज सेवा SEO पाइपलाइन के लिए क्वेरीज़ लॉग करती है:
log_entry = {
"timestamp": datetime.now(timezone.utc).isoformat(),
"query": query,
"filters_extracted": filters,
"results_count": len(results)
}
with open(SEO_LIVE_QUERIES_LOG, "a") as f:
f.write(json.dumps(log_entry) + "\n")
ये लॉग चरण 1d: लाइव क्वेरीज़ प्राप्त करें में वापस फीड होते हैं।