यहां कुछ "खेल के नियम" दिए गए हैं जिन्हें आपको इस समस्या को हल करने के लिए ध्यान में रखना चाहिए। आप शायद इन्हें पहले से ही जानते हैं, लेकिन इन्हें स्पष्ट रूप से बताने से अन्य पाठकों के लिए पुष्टि करने में मदद मिल सकती है।
- MySQL में सभी इंडेक्स एक बेस टेबल में केवल कॉलम को संदर्भित कर सकते हैं। आप एक पूर्ण-पाठ अनुक्रमणिका नहीं बना सकते जो अनेक तालिकाओं में अनुक्रमित हो।
- आप दृश्यों के लिए अनुक्रमणिका परिभाषित नहीं कर सकते, केवल आधार तालिकाएँ।
- एक
MATCH()
फुलटेक्स्ट इंडेक्स के खिलाफ क्वेरी को इंडेक्स में घोषित क्रम में फुलटेक्स्ट इंडेक्स के सभी कॉलम से मेल खाना चाहिए।
मैं उस सामग्री को संग्रहीत करने के लिए तीसरी तालिका बनाउंगा जिसे आप अनुक्रमणित करना चाहते हैं। इस सामग्री को अनावश्यक रूप से संग्रहीत करने की आवश्यकता नहीं है -- इसे केवल तीसरी तालिका में संग्रहीत करें। यह ऑब्जेक्ट-ओरिएंटेड डिज़ाइन से "कॉमन सुपरक्लास" की अवधारणा को उधार लेता है (जहां तक हम इसे RDBMS डिज़ाइन पर लागू कर सकते हैं)।
CREATE TABLE Searchable (
`id` SERIAL PRIMARY KEY,
`title` varchar(100) default NULL,
`description` text,
`keywords` text,
`url` varchar(255) default '',
FULLTEXT KEY `TitleDescFullText` (`keywords`,`title`,`description`,`url`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `shopitems` (
`id` INT UNSIGNED NOT NULL,
`ShopID` INT UNSIGNED NOT NULL,
`ImageID` INT UNSIGNED NOT NULL,
`pricing` varchar(45) NOT NULL,
`datetime_created` datetime NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (`id`) REFERENCES Searchable (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `shops` (
`id` INT UNSIGNED NOT NULL,
`owner_id` varchar(255) default NULL,
`datetime_created` datetime default NULL,
`created_by` varchar(255) default NULL,
`datetime_modified` datetime default NULL,
`modified_by` varchar(255) default NULL,
`overall_rating_avg` decimal(4,2) default '0.00',
PRIMARY KEY (`id`),
FOREIGN KEY (`id`) REFERENCES Searchable (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
ध्यान दें कि ऑटो-इन्क्रीमेंट कुंजी वाली एकमात्र तालिका अब Searchable
है . टेबल shops
और shopitems
संगत डेटा प्रकार वाली कुंजी का उपयोग करें, लेकिन ऑटो-इन्क्रीमेंट नहीं। तो आपको Searchable
. में एक पंक्ति बनानी होगी id
उत्पन्न करने के लिए मान, इससे पहले कि आप shops
. में संगत पंक्ति बना सकें या shopitems
।
मैंने FOREIGN KEY
जोड़ लिया है उदाहरण के लिए घोषणाएं, भले ही MyISAM चुपचाप इन बाधाओं को अनदेखा कर देगा (और आप पहले से ही जानते हैं कि आपको MyISAM का उपयोग पूर्ण पाठ अनुक्रमण के लिए समर्थन प्राप्त करने के लिए करना चाहिए)।
अब आप दोनों shops
. की पाठ्य सामग्री खोज सकते हैं और shopitems
एकल क्वेरी में, एकल पूर्ण पाठ अनुक्रमणिका का उपयोग करते हुए:
SELECT S.*, sh.*, si.*,
MATCH(keywords, title, description, url) AGAINST('dummy') As score
FROM Searchable S
LEFT OUTER JOIN shops sh ON (S.id = sh.id)
LEFT OUTER JOIN shopitems si ON (S.id = si.id)
WHERE MATCH(keywords, title, description, url) AGAINST('dummy')
ORDER BY score DESC;
बेशक, Searchable
. में दी गई पंक्ति के लिए केवल एक टेबल का मिलान होना चाहिए, या तो दुकान या दुकान की वस्तुएं, और इन तालिकाओं में अलग-अलग कॉलम हैं। तो या तो sh.*
या si.*
परिणाम में NULL होगा। अपने आवेदन में आउटपुट को प्रारूपित करना आप पर निर्भर है।
कुछ अन्य उत्तरों ने Sphinx Search का उपयोग करने का सुझाव दिया है . यह एक और तकनीक है जो MySQL को पूरक करती है और अधिक परिष्कृत पूर्ण-पाठ खोज क्षमता जोड़ती है। प्रश्नों के लिए इसका प्रदर्शन बहुत अच्छा है, इसलिए कुछ लोग इससे काफी मुग्ध हो गए हैं।
लेकिन अनुक्रमणिका बनाना और विशेष रूप से किसी अनुक्रमणिका में वृद्धिशील रूप से जोड़ना महंगा है। वास्तव में, Sphinx खोज अनुक्रमणिका को अद्यतन करना इतना महंगा है कि अनुशंसित समाधान पुराने, संग्रहीत डेटा के लिए एक अनुक्रमणिका और हाल ही के डेटा के लिए एक अन्य छोटी अनुक्रमणिका बनाना है जिसके अद्यतन होने की अधिक संभावना है। फिर प्रत्येक खोज को दो अलग-अलग अनुक्रमणिकाओं के विरुद्ध दो प्रश्नों को चलाने की आवश्यकता होती है। और यदि आपका डेटा स्वाभाविक रूप से पुराने डेटा के अपरिवर्तनीय होने के पैटर्न के अनुकूल नहीं है, तो आप वैसे भी इस ट्रिक का लाभ नहीं उठा पाएंगे।
अपनी टिप्पणी दोबारा दें:यहां Sphinx खोज दस्तावेज़ का एक अंश दिया गया है। किसी इंडेक्स के लाइव अपडेट के बारे में:
विचार यह है कि चूंकि स्फिंक्स खोज अनुक्रमणिका को अद्यतन करना महंगा है, इसलिए उनका समाधान आपके द्वारा अद्यतन की जाने वाली अनुक्रमणिका को यथासंभव छोटा बनाना है। ताकि केवल नवीनतम फ़ोरम पोस्ट (उनके उदाहरण में), जबकि संग्रहीत फ़ोरम पोस्ट का बड़ा इतिहास कभी नहीं बदलता है, इसलिए आप उस संग्रह के लिए एक बार दूसरी, बड़ी अनुक्रमणिका बनाते हैं। बेशक अगर आप एक खोज करना चाहते हैं, तो आपको दोनों इंडेक्स को क्वेरी करना होगा।
समय-समय पर, सप्ताह में एक बार कहें, "हाल के" फ़ोरम संदेशों को "संग्रहीत" माना जाएगा और आपको हाल की पोस्ट के लिए वर्तमान अनुक्रमणिका को संग्रहीत अनुक्रमणिका में मर्ज करना होगा, और छोटी अनुक्रमणिका को फिर से प्रारंभ करना होगा। उनका कहना है कि दो Sphinx सर्च इंडेक्स को मर्ज करना डेटा के अपडेट के बाद रीइंडेक्स करने की तुलना में अधिक कुशल है।
लेकिन मेरा कहना यह है कि हर डेटा सेट स्वाभाविक रूप से डेटा के संग्रहीत सेट के पैटर्न में नहीं आता है जो कभी नहीं बदलता है, बनाम हाल ही में अपडेट होने वाला डेटा।
उदाहरण के लिए अपना डेटाबेस लें:आपके पास दुकानें और दुकान हैं। आप इन्हें उन पंक्तियों में कैसे अलग कर सकते हैं जो कभी नहीं बदलतीं, बनाम नई पंक्तियाँ? कैटलॉग में किसी भी दुकान या उत्पादों को अपना विवरण अपडेट करने की अनुमति दी जानी चाहिए। लेकिन चूंकि हर बार जब आप कोई परिवर्तन करते हैं तो इसके लिए संपूर्ण Sphinx खोज अनुक्रमणिका के पुनर्निर्माण की आवश्यकता होती है, यह एक बहुत महंगा ऑपरेशन बन जाता है। शायद आप परिवर्तनों को कतारबद्ध करेंगे और उन्हें एक बैच में लागू करेंगे, सप्ताह में एक बार अनुक्रमणिका का पुनर्निर्माण करेंगे। लेकिन दुकान विक्रेताओं को यह समझाने की कोशिश करें कि उनकी दुकान के विवरण में मामूली बदलाव रविवार की रात तक प्रभावी क्यों नहीं होगा।