बहुत सारी जाँच-पड़ताल के बाद मैंने पाया कि समस्या इस बात से आती है कि व्यवस्थापक खोज फ़ील्ड के लिए खोज क्वेरी कैसे बनाई जाती है (ChangeList
में) कक्षा)। एक बहु-शब्द खोज में (रिक्त स्थान से अलग किए गए शब्द) प्रत्येक शब्द को एक नया filter()
श्रृंखलाबद्ध करके QuerySet में जोड़ा जाता है . जब search_fields
. में एक या अधिक संबंधित फ़ील्ड हों , बनाई गई SQL क्वेरी में बहुत सारे JOIN
होंगे कई JOIN
. के साथ एक के बाद एक जंजीर में जकड़े प्रत्येक संबंधित क्षेत्र के लिए (मेरा संबंधित प्रश्न
कुछ उदाहरणों और अधिक जानकारी के लिए)। JOIN
. की यह श्रृंखला क्या ऐसा इसलिए है कि प्रत्येक शब्द केवल पूर्ववर्ती शब्द द्वारा डेटा फ़िल्टर के सबसेट में खोजा जाएगा और, सबसे महत्वपूर्ण बात यह है कि एक संबंधित फ़ील्ड में मिलान करने के लिए केवल एक शब्द (बनाम सभी शब्दों की आवश्यकता होती है) की आवश्यकता होती है। देखें बहु-मूल्यवान रिश्तों का विस्तार
ए> इस विषय पर अधिक जानकारी के लिए Django दस्तावेज़ों में। मुझे पूरा यकीन है कि यह वही व्यवहार है जो अधिकांश समय व्यवस्थापक खोज फ़ील्ड के लिए चाहता था।
इस क्वेरी का दोष (संबंधित क्षेत्रों के साथ) यह है कि प्रदर्शन में भिन्नता (क्वेरी करने का समय) वास्तव में बड़ी हो सकती है। यह बहुत सारे कारकों पर निर्भर करता है:खोजे गए शब्दों की संख्या, खोजे गए शब्द, फ़ील्ड खोज का प्रकार (VARCHAR, आदि), फ़ील्ड खोज की संख्या, तालिकाओं में डेटा, तालिकाओं का आकार, आदि। सही संयोजन के साथ यह आसान है एक प्रश्न है जो अधिकतर हमेशा के लिए ले जाएगा (एक प्रश्न जो 10 मिनट से अधिक समय लेता है। मेरे लिए एक प्रश्न है जो इस खोज क्षेत्र के संदर्भ में हमेशा के लिए लेता है)।
इतना समय लगने का कारण यह है कि डेटाबेस को प्रत्येक शब्द के लिए एक अस्थायी तालिका बनाने की आवश्यकता होती है और अगले शब्द की खोज के लिए इसे पूरी तरह से स्कैन करना पड़ता है। तो, यह वास्तव में जल्दी जुड़ जाता है।
प्रदर्शन को बेहतर बनाने के लिए एक संभावित बदलाव ANDed . करना है एक ही filter()
में सभी शब्द . इस तरह उनका केवल एक ही होगा JOIN
संबंधित क्षेत्र द्वारा (या 2 यदि यह अनेक से अनेक है) के बजाय और भी बहुत कुछ। यह क्वेरी बहुत तेज़ और वास्तव में छोटे प्रदर्शन भिन्नता के साथ होगी। दोष यह है कि संबंधित फ़ील्ड में मिलान करने के लिए सभी शर्तें होनी चाहिए, इसलिए, आप कई मामलों में कम मिलान प्राप्त कर सकते हैं।
अपडेट करें
जैसा कि ट्रिंचेट . ने पूछा है खोज व्यवहार में परिवर्तन करने के लिए यहां क्या आवश्यक है (Django 1.7 के लिए)। आपको get_search_results()
. को ओवरराइड करना होगा व्यवस्थापक वर्ग जहाँ आप इस प्रकार की खोज चाहते हैं। आपको बेस क्लास से सभी मेथड कोड को कॉपी करना होगा (ModelAdmin
) अपनी कक्षा के लिए। फिर आपको उन पंक्तियों को बदलना होगा:
for bit in search_term.split():
or_queries = [models.Q(**{orm_lookup: bit})
for orm_lookup in orm_lookups]
queryset = queryset.filter(reduce(operator.or_, or_queries))
उसके लिए:
and_queries = []
for bit in search_term.split():
or_queries = [models.Q(**{orm_lookup: bit})
for orm_lookup in orm_lookups]
and_queries.append(Q(reduce(operator.or_, or_queries)))
queryset = queryset.filter(reduce(operator.and_, and_queries))
इस कोड का परीक्षण नहीं किया गया है। मेरा मूल कोड Django 1.4 के लिए था और मैं इसे यहां 1.7 के लिए अनुकूलित करता हूं।