टैग सिस्टम कैसे लागू करें


90

मैं सोच रहा था कि टैग प्रणाली को लागू करने का सबसे अच्छा तरीका क्या है, जैसे कि एसओ पर इस्तेमाल किया गया। मैं यह सोच रहा था, लेकिन मैं एक अच्छा मापनीय समाधान के साथ नहीं आ सकता।

मैं एक बुनियादी 3 टेबल समाधान होने के बारे में सोच रहा था: एक tagsटेबल, एक articlesटेबल और एक tag_to_articlesटेबल होना।

क्या यह इस समस्या का सबसे अच्छा समाधान है, या विकल्प हैं? इस पद्धति का उपयोग करने से समय में तालिका बहुत बड़ी हो जाएगी, और इसे खोजने के लिए बहुत अधिक कुशल नहीं हूं। दूसरी ओर यह महत्वपूर्ण नहीं है कि क्वेरी तेजी से निष्पादित हो।


जवाबों:


119

मुझे विश्वास है कि आपको यह ब्लॉग पोस्ट दिलचस्प लगेगा: टैग: डेटाबेस स्कीमा

समस्या: आप एक डेटाबेस स्कीमा रखना चाहते हैं, जहाँ आप एक बुकमार्क (या ब्लॉग पोस्ट या जो भी चाहें) टैग कर सकते हैं। बाद में, आप बुकमार्क को संघ या टैग के प्रतिच्छेदन के लिए विवश करना चाहते हैं। आप खोज परिणाम से कुछ टैग (कहना: घटाएँ) भी छोड़ना चाहते हैं।

"MySQLicious" समाधान

इस समाधान में, स्कीमा को सिर्फ एक तालिका मिली है, यह अपभ्रंश है। इस प्रकार को "MySQLicious solution" कहा जाता है क्योंकि MySQLicious इस संरचना के साथ एक तालिका में del.icio.us डेटा आयात करता है।

यहाँ छवि विवरण दर्ज करेंयहाँ छवि विवरण दर्ज करें

"खोज + webservice + semweb" के लिए अंतर (और) क्वेरी:

SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
AND tags LIKE "%webservice%"
AND tags LIKE "%semweb%"

संघ (OR) "खोज | webservice | semweb" के लिए प्रश्न:

SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
OR tags LIKE "%webservice%"
OR tags LIKE "%semweb%"

"खोज + webservice-semweb" के लिए माइनस क्वेरी

SELECT *
FROM `delicious`
WHERE tags LIKE "%search%"
AND tags LIKE "%webservice%"
AND tags NOT LIKE "%semweb%"

"स्कटल" समाधान

स्कूटल अपने डेटा को दो तालिकाओं में व्यवस्थित करता है। वह तालिका “scCategories” “tag” -table है और “बुकमार्क” -table के लिए एक विदेशी कुंजी मिली है।

यहाँ छवि विवरण दर्ज करें

"बुकमार्क + webservice + semweb" के लिए अंतर्ग्रहण (और) क्वेरी:

SELECT b.*
FROM scBookmarks b, scCategories c
WHERE c.bId = b.bId
AND (c.category IN ('bookmark', 'webservice', 'semweb'))
GROUP BY b.bId
HAVING COUNT( b.bId )=3

सबसे पहले, सभी बुकमार्क-टैग संयोजनों को खोजा जाता है, जहां टैग "बुकमार्क", "वेबसेवा" या "सेमीवेब" (सी.कैटोरी आईएन ('बुकमार्क', 'वेबसर्विस', 'सेमवेब')) है, फिर बस वह बुकमार्क जो खोजे गए सभी तीन टैग को ध्यान में रखा गया (HAVING COUNT (b.bId) = 3)।

संघ (OR) "बुकमार्क | वेबसेवा | सेमीवेब" के लिए क्वेरी: बस बाहर निकलने वाले खंड को छोड़ दें और आप संघ:

SELECT b.*
FROM scBookmarks b, scCategories c
WHERE c.bId = b.bId
AND (c.category IN ('bookmark', 'webservice', 'semweb'))
GROUP BY b.bId

माइनस (अपवर्जन) क्वेरी "बुकमार्क + वेबसर्विस-सेमीवेब" के लिए, वह है: बुकमार्क और वेबसर्विस और नॉट वीवीईबी।

SELECT b. *
FROM scBookmarks b, scCategories c
WHERE b.bId = c.bId
AND (c.category IN ('bookmark', 'webservice'))
AND b.bId NOT
IN (SELECT b.bId FROM scBookmarks b, scCategories c WHERE b.bId = c.bId AND c.category = 'semweb')
GROUP BY b.bId
HAVING COUNT( b.bId ) =2

HAVING COUNT को छोड़ने से "बुकमार्क | webservice-semweb" के लिए क्वेरी होती है।


"टोक्सी" समाधान

टोक्सी एक तीन-टेबल संरचना के साथ आया था। तालिका "टैगमैप" के माध्यम से बुकमार्क और टैग एन-टू-मी संबंधित हैं। प्रत्येक टैग का उपयोग विभिन्न बुकमार्क्स और इसके विपरीत के साथ किया जा सकता है। इस DB- स्कीमा का उपयोग वर्डप्रेस द्वारा भी किया जाता है। प्रश्न "स्क्रटल" समाधान के समान हैं।

यहाँ छवि विवरण दर्ज करें

"बुकमार्क + webservice + semweb" के लिए अंतर (और) क्वेरी

SELECT b.*
FROM tagmap bt, bookmark b, tag t
WHERE bt.tag_id = t.tag_id
AND (t.name IN ('bookmark', 'webservice', 'semweb'))
AND b.id = bt.bookmark_id
GROUP BY b.id
HAVING COUNT( b.id )=3

संघ (OR) "बुकमार्क | वेबसेवा | सेमीवेब" के लिए प्रश्न

SELECT b.*
FROM tagmap bt, bookmark b, tag t
WHERE bt.tag_id = t.tag_id
AND (t.name IN ('bookmark', 'webservice', 'semweb'))
AND b.id = bt.bookmark_id
GROUP BY b.id

माइनस (अपवर्जन) क्वेरी "बुकमार्क + वेबसर्विस-सेमीवेब" के लिए, वह है: बुकमार्क और वेबसर्विस और नॉट वीवीईबी।

SELECT b. *
FROM bookmark b, tagmap bt, tag t
WHERE b.id = bt.bookmark_id
AND bt.tag_id = t.tag_id
AND (t.name IN ('Programming', 'Algorithms'))
AND b.id NOT IN (SELECT b.id FROM bookmark b, tagmap bt, tag t WHERE b.id = bt.bookmark_id AND bt.tag_id = t.tag_id AND t.name = 'Python')
GROUP BY b.id
HAVING COUNT( b.id ) =2

HAVING COUNT को छोड़ने से "बुकमार्क | webservice-semweb" के लिए क्वेरी होती है।


3
उस ब्लॉग पोस्ट के लेखक यहाँ। ब्लॉग अब क्रोम (बेवकूफ वर्डप्रेस कमजोरियों, अब tumblr में स्थानांतरित) द्वारा अवरुद्ध नहीं है।
कुदोस

हाय @ फीलिप। ठीक है, मेरे उत्तर को संपादित किया। BTW, डेटाबेस टैग सिस्टम पर शानदार पोस्ट के लिए धन्यवाद।
निक डंडौलकिस

1
बस एक नोट के रूप में: यदि आप 'बुकमार्क' और 'वेबसर्विस' के लिए खोजे गए बुकमार्क को दिखाने के लिए टोक्सी समाधान के लिए इंटरसेक्शन क्वेरी चाहते थे, तो आपको "HAVING COUNT (bid.id = 3") से बदलना होगा 3 से "साइज़ोफ़ (सरणी ('बुकमार्क', 'वेबसर्विस'))"। यदि आप इसे डायनामिक टैग क्वेरी फ़ंक्शन के रूप में उपयोग करने की योजना बनाते हैं तो बस एक छोटा सा विवरण।
टोक्सीप्ट

3
पोस्ट में उल्लिखित विभिन्न समाधानों के लिए प्रदर्शन की तुलना के लिए कोई लिंक?
kampta

@kampta, नहीं, मेरे पास कोई लिंक नहीं है।
निक डंडौलकिस

8

आपके तीन-टेबल समाधान के साथ कुछ भी गलत नहीं है।

एक अन्य विकल्प उन लेखों की संख्या को सीमित करना है जो एक लेख पर लागू हो सकते हैं (जैसे 5 एसओ में) और सीधे अपने लेख तालिका में जोड़ें।

डीबी को सामान्य करने के अपने फायदे और कमियां हैं, जैसे हार्ड-वायरिंग चीजों को एक टेबल में रखने से फायदे और कमियां हैं।

कुछ भी नहीं तुम दोनों नहीं कर सकते कहते हैं। यह सूचना को दोहराने के लिए संबंधपरक DB प्रतिमानों के खिलाफ जाता है, लेकिन यदि लक्ष्य प्रदर्शन है तो आपको प्रतिमानों को तोड़ना पड़ सकता है।


हां, लेख तालिका में सीधे टैग डालना निश्चित रूप से एक विकल्प होगा, हालांकि इस पद्धति में कुछ कमियां हैं। यदि आप 5 टैग को अल्पविराम से अलग किए गए फ़ील्ड की तरह संग्रहीत करते हैं (tag1,2,3,4), तो यह एक आसान तरीका होगा। सवाल यह है कि अगर खोज किसी भी तेजी से आगे बढ़ेगी। उदाहरण के लिए कोई व्यक्ति टैग 1 के साथ सब कुछ देखना चाहता है, आपको पूरे लेख तालिका को गर्त में जाना होगा। यह कम हो जाएगा तो फिर टैग_टोली टेबल को गर्त में ले जाएगा। लेकिन तब फिर से, tag_to_article टेबल स्लिमर है। एक और बात यह है कि आपको हर बार php में विस्फोट करना होगा, मुझे नहीं पता कि इसमें समय लगता है या नहीं।
सैफ बिंच

यदि आप दोनों करते हैं (टैग w / लेख, और अलग-अलग तालिका में) तो यह आपको पोस्ट-केंद्रित खोजों और टैग-केंद्रित खोजों के लिए दोनों का प्रदर्शन देता है। ट्रेडऑफ़ बार-बार सूचना को बनाए रखने का बोझ है। इसके अलावा, टैग की संख्या को सीमित करके, आप प्रत्येक को अपने कॉलम में डाल सकते हैं। बस उन लेखों से * चुनें जहां XXXXX और जाते हैं; कोई विस्फोट आवश्यक नहीं है।
जॉन

6

आपका प्रस्तावित तीन टेबल कार्यान्वयन टैगिंग के लिए काम करेगा।

स्टैक ओवरफ्लो का उपयोग करता है, हालांकि, अलग कार्यान्वयन। वे सादे पाठ में पोस्ट तालिका में varchar स्तंभ के लिए टैग संग्रहीत करते हैं और टैग मिलान करने वाले पोस्ट लाने के लिए पूर्ण पाठ अनुक्रमण का उपयोग करते हैं। उदाहरण के लिए posts.tags = "algorithm system tagging best-practices"। मुझे यकीन है कि जेफ ने इसका कहीं उल्लेख किया है लेकिन मैं भूल जाता हूं कि कहां है।


4
यह सुपर अक्षम लगता है। टैग ऑर्डर के बारे में क्या? या संबंधित टैग? (जैसे कि "प्रक्रिया" "एल्गोरिथम" या इसके समान कुछ होने के समान है)
रिचर्ड ड्यूयर

3

प्रस्तावित समाधान सबसे अच्छा है, केवल-व्यावहारिक ही नहीं है- जिस तरह से मैं टैग और लेखों के बीच कई-से-कई संबंधों को संबोधित करने के बारे में सोच सकता हूं। इसलिए मेरा वोट 'हां, यह अभी भी सबसे अच्छा है।' मुझे किसी भी विकल्प में दिलचस्पी होगी।


मैं सहमत हूँ। इन टैग और टैगपॉइंट टेबल का रिकॉर्ड छोटा होता है और जब ठीक से अनुक्रमित किया जाता है तो नाटकीय रूप से प्रदर्शन को कम नहीं करना चाहिए। प्रति आइटम नंबर सीमित टैग भी एक अच्छा विचार हो सकता है।
पनजेक

2

यदि आपका डेटाबेस अनुक्रमणिका सरणियों (उदाहरण के लिए, जैसे PostgreSQL) का समर्थन करता है, तो मैं एक ही तालिका पर स्ट्रिंग्स के एक सरणी के रूप में पूरी तरह से असंगत समाधान - स्टोर टैग की सिफारिश करूंगा। यदि नहीं, तो ऑब्जेक्ट्स को टैग करने के लिए द्वितीयक तालिका मैप करना सबसे अच्छा समाधान है। यदि आपको टैग के खिलाफ अतिरिक्त जानकारी संग्रहीत करने की आवश्यकता है, तो आप एक अलग टैग तालिका का उपयोग कर सकते हैं, लेकिन हर टैग लुकअप के लिए एक दूसरे में शामिल होने का कोई मतलब नहीं है।


POstgreSQL पूर्णांक सरणियों पर केवल अनुक्रमणिका का समर्थन करता है: postgresql.org/docs/current/static/intarray.html
माइक चेम्बरलेन

1
Nowadys यह पाठ का भी समर्थन करता है: postgresql.org/docs/9.6/static/arrays.html
luckydonald

2

मैं बेहतर प्रदर्शन के लिए अनुकूलित MySQLicious का सुझाव देना चाहूंगा। इससे पहले टोक्सी (3 टेबल) समाधान की कमियां है

यदि आपके पास लाखों प्रश्न हैं, और इसमें प्रत्येक में 5 टैग हैं, तो टैगमैप तालिका में 5 मिलियन प्रविष्टियां होंगी। इसलिए पहले हमें टैग खोज के आधार पर 10 हजार टैगमैप प्रविष्टियों को फ़िल्टर करना होगा और फिर उन 10 हजार के मिलान वाले प्रश्नों को फ़िल्टर करना होगा। इसलिए फ़िल्टर करते समय अगर आर्टिस्टिक आईडी सिंपल न्यूमेरिक है तो ठीक है, लेकिन अगर यह UUID (32 varchar) की तरह है तो फ़िल्टरिंग को बड़ी तुलना की जरूरत है, हालांकि इसे अनुक्रमित किया गया है।

मेरा समाधान:

जब भी नया टैग बनाया जाता है, तो काउंटर ++ (बेस 10) रखें, और उस काउंटर को बेस 64 में परिवर्तित करें। अब प्रत्येक टैग नाम में आधार 64 आईडी होगी। और इस आईडी को नाम के साथ UI में पास करें। इस तरह से आपके पास अधिकतम दो चार आईडी होंगे, जब तक कि हमारे सिस्टम में 4095 टैग न हों। अब प्रत्येक प्रश्न तालिका टैग कॉलम में इन एकाधिक टैगों को संक्षिप्त करें। साथ ही सीमांकक जोड़ें और इसे सॉर्ट करें।

तो तालिका इस तरह दिखती है

यहाँ छवि विवरण दर्ज करें

क्वेरी करते समय, वास्तविक टैग नाम के बजाय आईडी पर क्वेरी करें। चूंकि यह SORTED है , इसलिए andटैग पर स्थिति अधिक कुशल ( LIKE '%|a|%|c|%|f|%) होगी।

ध्यान दें कि सिंगल स्पेस सीमांकक पर्याप्त नहीं है और हमें टैग्स को अलग-अलग करने के लिए डबल सीमांकक की आवश्यकता है sqlऔर mysqlक्योंकि परिणाम LIKE "%sql%"वापस भी आएंगे mysql। होना चाहिएLIKE "%|sql|%"

मुझे पता है कि खोज गैर-अनुक्रमित है लेकिन फिर भी आप लेख से संबंधित अन्य स्तंभों पर अनुक्रमित हो सकते हैं जैसे कि लेखक / तिथि समय और अन्य पूर्ण तालिका स्कैन के लिए नेतृत्व करेंगे।

अंत में इस समाधान के साथ, किसी भी आंतरिक जुड़ाव की आवश्यकता नहीं है जहाँ मिलियन रिकॉर्ड्स की तुलना ज्वाइन कंडीशन पर 5 मिलियन रिकॉर्ड्स से की जानी है।


टीम, कृपया टिप्पणी में इस समाधान की कमी पर अपना इनपुट प्रदान करें।
कानागावेलु सुगुमार

@ नीक डंडौलाकिस उपरोक्त समाधान पर अपनी टिप्पणी प्रदान करके कृपया मेरी सहायता करें?
कानागावेलु सुगुमार

@ जूहा सिरजला क्या उपरोक्त समाधान ठीक है?
कानागावेलु सुगुमार

0
CREATE TABLE Tags (
    tag VARHAR(...) NOT NULL,
    bid INT ... NOT NULL,
    PRIMARY KEY(tag, bid),
    INDEX(bid, tag)
)

टिप्पणियाँ:

  • यह TOXI से बेहतर है कि यह एक अतिरिक्त से नहीं गुजरती है: कई तालिका जो अनुकूलन को कठिन बनाती है।
  • निश्चित रूप से, मेरा दृष्टिकोण अनावश्यक टैग्स के कारण थोड़ा अधिक (TOXI की तुलना में) हो सकता है, लेकिन यह पूरे डेटाबेस का एक छोटा प्रतिशत है , और प्रदर्शन में सुधार महत्वपूर्ण हो सकता है।
  • यह अत्यधिक स्केलेबल है।
  • यह नहीं है (क्योंकि इसकी जरूरत नहीं है) एक सरोगेट AUTO_INCREMENTपीके। इसलिए, यह स्कूटल से बेहतर है।
  • (MySQLicious बेकार है, क्योंकि यह एक सूचकांक का उपयोग नहीं कर सकते हैं LIKEके साथ अग्रणी ; सबस्ट्रिंग पर झूठी हिट वाइल्ड कार्ड)
  • MySQL के लिए, 'क्लस्टरिंग' प्रभाव प्राप्त करने के लिए Engine = InnoDB का उपयोग करना सुनिश्चित करें।

संबंधित चर्चा (MySQL के लिए):
कई: कई मैपिंग टेबल ऑप्टिमाइज़ेशन
सूचियों का आदेश दिया

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.