टैगिंग के लिए डेटाबेस डिजाइन


171

आप निम्नलिखित टैगिंग सुविधाओं का समर्थन करने के लिए एक डेटाबेस कैसे डिज़ाइन करेंगे:

  • आइटम में बड़ी संख्या में टैग हो सकते हैं
  • दिए गए सेट के साथ टैग किए गए सभी आइटम की खोज त्वरित होनी चाहिए (आइटम में सभी टैग होने चाहिए, इसलिए यह एक-खोज है, न कि एक-खोज)
  • त्वरित लुकअप / रीडिंग को सक्षम करने के लिए आइटम बनाना / लिखना धीमा हो सकता है

आदर्श रूप से, सभी आइटमों की खोज, जो किसी दिए गए टैग का एक सेट (कम से कम) एक एसक्यूएल स्टेटमेंट का उपयोग करके किया जाना चाहिए। चूंकि टैग की संख्या के साथ-साथ किसी भी आइटम पर टैग की संख्या अज्ञात है और उच्च हो सकती है, जोइन का उपयोग करना अव्यावहारिक है।

कोई विचार?


अब तक के सभी उत्तरों के लिए धन्यवाद।

यदि मैं गलत नहीं हूँ, हालाँकि, दिए गए उत्तर दिखाते हैं कि टैग पर OR-search कैसे किया जाता है। (वे सभी आइटम चुनें जिनमें एक या एक से अधिक एन टैग हैं)। मैं एक कुशल और खोज की तलाश में हूं। (वे सभी आइटम चुनें जिनमें सभी n टैग हैं - और संभवतः अधिक।)

जवाबों:


22

एंडिंग के बारे में: ऐसा लगता है कि आप "रिलेशनल डिवीजन" ऑपरेशन की तलाश कर रहे हैं। यह लेख संक्षिप्त और अभी तक समझने योग्य तरीके से संबंधपरक विभाजन को शामिल करता है।

प्रदर्शन के बारे में: एक बिटमैप-आधारित दृष्टिकोण सहज रूप से लगता है कि यह स्थिति को अच्छी तरह से सूट करेगा। हालांकि, मुझे यकीन नहीं है कि बिटमैप इंडेक्सिंग को "मैन्युअल रूप से" लागू करना एक अच्छा विचार है, जैसे कि डिजीगुरु का सुझाव है: जब भी नए टैग जोड़े जाते हैं तो यह एक जटिल स्थिति की तरह लगता है (लेकिन? उपयोग का हो सकता है, क्योंकि एक अंतर्निहित अनुक्रमण प्रणाली अनुरक्षण रखरखाव की संभावित जटिलता को दूर करती है; इसके अलावा, बिटमैप इंडेक्स की पेशकश करने वाला एक डीबीएमएस क्वेरी प्लान करते समय उचित तरीके से उन पर विचार करने में सक्षम होना चाहिए।


4
मेरा कहना है कि उत्तर थोड़ा संक्षिप्त है, क्योंकि डेटाबेस के एक बिट फ़ील्ड प्रकार का उपयोग करने से आप बिट की एक विशिष्ट संख्या तक सीमित हो जाते हैं। इसका मतलब यह नहीं है कि प्रत्येक आइटम एक निश्चित संख्या में टैग तक सीमित है, लेकिन यह कि पूरे सिस्टम में केवल कुछ विशिष्ट टैग हो सकते हैं (आमतौर पर 32 या 64 तक)।
मार्क रेनॉफ

1
3nf कार्यान्वयन (प्रश्न, टैग, Question_has_Tag) और बिटमैप इंडेक्स को Question_has_Tag पर मानकर, बिटमैप इंडेक्स को हर बार एक प्रश्न में एक टैग जोड़ा या हटाए जाने पर पुनर्निर्माण करना पड़ता है। एक ऐसा प्रश्न select * from question q inner join question_has_tag qt where tag_id in (select tag_id from tags where (what we want) minus select tag_id from tags where (what we don't)ठीक होना चाहिए और सही बी-ट्री इंडेक्स मानकर स्केल आउट किया जाए
एडम मूस

"यह लेख" लिंक मृत है। मुझे यह पढ़ना पसंद था कि :(
एमपीएन

3
निशान: यह एक अच्छा लग रहा है: simple-talk.com/sql/t-sql-programming/… यह संभवतः मेरे द्वारा संदर्भित एक का पुन: प्रकाशित संस्करण है।
Troels Arvin

लेख का URL अब मान्य नहीं है
सेबस्टियन एच।

77

यहाँ डेटाबेस स्कीमा टैग करने पर एक अच्छा लेख है:

http://howto.philippkeller.com/2005/04/24/Tags-Database-schemas/

प्रदर्शन परीक्षणों के साथ:

http://howto.philippkeller.com/2005/06/19/Tagsystems-performance-tests/

ध्यान दें कि MySQL के लिए निष्कर्ष बहुत ही विशिष्ट हैं, जो (कम से कम 2005 में उस समय लिखा गया था) में बहुत खराब पूर्ण पाठ अनुक्रमण विशेषताएँ थीं।


1
आपको एसओ के साथ टैगिंग सिस्टम को लागू करने के तरीके के बारे में अधिक विस्तृत तकनीकी जानकारी देना अच्छा लगेगा। मुझे लगता है कि आपने एक पॉडकास्ट पर कहा था कि आप हर सवाल के साथ सभी टैग्स को एक कॉलम में रखते हैं और फिर उड़ने पर उन्हें क्रमबद्ध / डी-सीरियल करते हैं? मैं इसके बारे में अधिक जानना पसंद करूंगा और शायद कुछ कोड स्निपेट देखूं। मैं चारों ओर देख रहा हूं और कोई विवरण पाया है, क्या कोई लिंक है जहां आप मेटा से सवाल पूछने से पहले ही ऐसा कर चुके हैं?
मारस्टन ए।

5
मेटा पर इस सवाल का SO स्कीमा पर कुछ जानकारी है: meta.stackexchange.com/questions/1863/so-database-schema
Barrett

मूल लिंक मृत थे, लेकिन मुझे लगता है कि मुझे उनका नया स्थान मिल गया। आप यह सत्यापित करना चाह सकते हैं कि ये वे लेख थे जिनका आप उल्लेख कर रहे थे।
ब्रैड लार्सन

12
@ जेफ़ द्वारा लिखे जाने के बावजूद, यह अभी भी अनिवार्य रूप से एक लिंक है जो केवल उत्तर देता है।
curiousdannii

13

मुझे सीधे समाधान के साथ कोई समस्या नहीं दिखती है: आइटम के लिए तालिका, टैग के लिए तालिका, "टैगिंग" के लिए क्रॉसस्टेबल

क्रॉस टेबल पर संकेतक पर्याप्त अनुकूलन होना चाहिए। उपयुक्त वस्तुओं का चयन करना होगा

SELECT * FROM items WHERE id IN  
    (SELECT DISTINCT item_id FROM item_tag WHERE  
    tag_id = tag1 OR tag_id = tag2 OR ...)  

और टैगिंग होगी

SELECT * FROM items WHERE  
    EXISTS (SELECT 1 FROM item_tag WHERE id = item_id AND tag_id = tag1)  
    AND EXISTS (SELECT 1 FROM item_tag WHERE id = item_id AND tag_id = tag2)  
    AND ...

जो बड़े पैमाने पर तुलनात्मक टैग के लिए इतना कुशल नहीं है। यदि आप मेमोरी में टैग काउंट बनाए रखना चाहते हैं, तो आप उन टैग्स के साथ शुरुआत करने के लिए क्वेरी कर सकते हैं जो अक्सर नहीं होते हैं, इसलिए और अनुक्रम का त्वरित मूल्यांकन किया जाएगा। टैग की अपेक्षित संख्या के आधार पर मिलान किया जा सकता है और उनमें से किसी एक के मिलान की अपेक्षा के अनुसार यह ठीक हो सकता है, यदि आप 20 टैग से मेल खाते हैं, और उम्मीद करते हैं कि कुछ यादृच्छिक आइटम उनमें से 15 से मेल खाएंगे, तो यह अभी भी भारी होगा एक डेटाबेस पर।


13

मैं सिर्फ इस बात को उजागर करना चाहता था कि @Jeff Atwood का लिंक ( http://howto.philippkeller.com/2005/04/24/Tags-Database-schemas/ ) से बहुत गहरा संबंध है (यह 3 अलग-अलग स्कीमा के गुणों की चर्चा करता है) दृष्टिकोण) और AND प्रश्नों के लिए एक अच्छा समाधान है जो आमतौर पर यहां अब तक बताए गए से बेहतर प्रदर्शन करेंगे (यानी यह प्रत्येक शब्द के लिए सहसंबंधित उपशम का उपयोग नहीं करता है)। टिप्पणियों में बहुत सारी अच्छी चीजें भी।

ps - जिस दृष्टिकोण के बारे में हर कोई यहाँ बात कर रहा है उसे लेख में "टोक्सी" समाधान के रूप में जाना जाता है।


3
मुझे उस महान लेख को पढ़ना याद है, लेकिन दुर्भाग्य से लिंक अब मृत है। :( किसी को भी इसके बारे में पता है?
लोकलहोस्ट

5
लिंक मृत था: <
हारून

6

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

उपयुक्त कैशिंग मैकेनिज्म के साथ यह समाधान संभवतः एक घरेलू समाधान की तुलना में बेहतर प्रदर्शन देगा।

हालाँकि, मैं वास्तव में नहीं सोचता कि एक छोटे या मध्यम आकार के अनुप्रयोग में आपको पहले के पोस्ट में वर्णित सामान्यीकृत डेटाबेस की तुलना में अधिक परिष्कृत कार्यान्वयन की आवश्यकता होगी।

EDIT: आपके स्पष्टीकरण के साथ यह एक खोज इंजन के साथ JCR जैसे समाधान का उपयोग करने के लिए अधिक सम्मोहक लगता है। यह लंबे समय में आपके कार्यक्रमों को बहुत सरल करेगा।


5

सबसे आसान तरीका टैग टेबल बनाना है ।
Target_Type- यदि आप कई तालिकाओं को टैग कर रहे हैं
Target- रिकॉर्ड की कुंजी टैग की जा रही है
Tag- एक टैग का पाठ

डेटा को छोड़ना कुछ इस तरह होगा:

Select distinct target from tags   
where tag in ([your list of tags to search for here])  
and target_type = [the table you're searching]

अद्यतन
आपकी शर्तों और शर्तों के आधार पर, ऊपर दी गई क्वेरी कुछ इस तरह से बदल जाएगी

select target
from (
  select target, count(*) cnt 
  from tags   
  where tag in ([your list of tags to search for here])
    and target_type = [the table you're searching]
)
where cnt = [number of tags being searched]

1

मैं दूसरा @Zizzencs सुझाव देता हूं कि आप ऐसा कुछ चाहते हैं जो पूरी तरह से (R) DB- केंद्रित न हो

किसी तरह, मेरा मानना ​​है कि कुछ उचित कैशिंग / इंडेक्सिंग के साथ उस टैग को स्टोर करने के लिए सादे नवरचेर फ़ील्ड्स का उपयोग करने से तेज़ परिणाम मिल सकते हैं। लेकिन वह सिर्फ मैं हूं।

मैंने कई आइटम से पहले (आइटम टैग आइटमटैग) का प्रतिनिधित्व करने के लिए 3 तालिकाओं का उपयोग करके टैगिंग सिस्टम लागू किया है, लेकिन मुझे लगता है कि आप बहुत से स्थानों पर टैग के साथ काम करेंगे, मैं आपको बता सकता हूं कि 3 तालिकाओं के साथ सभी समय पर एक साथ हेरफेर / queried किया जाना निश्चित रूप से आपके कोड को और अधिक जटिल बना देगा।

आप विचार करना चाह सकते हैं कि क्या जोड़ा जटिलता इसके लायक है।


0

आप जुड़ने से बच नहीं पाएंगे और फिर भी कुछ हद तक सामान्य हो जाएंगे।

मेरा दृष्टिकोण एक टैग तालिका है।

 TagId (PK)| TagName (Indexed)

उसके बाद, आपके आइटम तालिका में एक TagXREFID कॉलम है।

यह TagXREFID कॉलम एक 3rd टेबल के लिए एक FK है, मैं इसे TagXREF कहूंगा:

 TagXrefID | ItemID | TagId

तो, एक आइटम के लिए सभी टैग प्राप्त करने के लिए कुछ इस तरह होगा:

SELECT Tags.TagId,Tags.TagName 
     FROM Tags,TagXref 
     WHERE TagXref.TagId = Tags.TagId 
         AND TagXref.ItemID = @ItemID

और एक टैग के लिए सभी आइटम प्राप्त करने के लिए, मैं इस तरह से कुछ का उपयोग करूंगा:

SELECT * FROM Items, TagXref
     WHERE TagXref.TagId IN 
          ( SELECT Tags.TagId FROM Tags
                WHERE Tags.TagName = @TagName; )
     AND Items.ItemId = TagXref.ItemId;

एक साथ टैग का एक गुच्छा और करने के लिए, आप उपरोक्त कथन को थोड़ा जोड़ने के लिए संशोधित करना होगा और टैग। नाम = @ टैगनाम और टैग.टैगनेम = @ टैगनाम 2 आदि ... और गतिशील रूप से क्वेरी बनाएँ।


0

मुझे जो करना पसंद है, उसमें कई टेबल हैं जो कच्चे डेटा का प्रतिनिधित्व करते हैं, इसलिए इस मामले में आपके पास होगा

Items (ID pk, Name, <properties>)
Tags (ID pk, Name)
TagItems (TagID fk, ItemID fk)

यह लिखने के समय के लिए तेजी से काम करता है, और सब कुछ सामान्यीकृत रखता है, लेकिन आप यह भी नोट कर सकते हैं कि प्रत्येक टैग के लिए, आपको हर उस अतिरिक्त टैग के लिए दो बार जुड़ना होगा, जिसे आप चाहते हैं, इसलिए यह धीमा पढ़ने के लिए है।

पढ़ने में सुधार करने के लिए एक समाधान एक संग्रहीत कार्यविधि स्थापित करके कमांड पर एक कैशिंग तालिका बनाना है जो अनिवार्य रूप से एक नई तालिका बनाता है जो एक चपटा प्रारूप में डेटा का प्रतिनिधित्व करता है ...

CachedTagItems(ID, Name, <properties>, tag1, tag2, ... tagN)

तब आप विचार कर सकते हैं कि कितनी बार टैग की गई आइटम तालिका को अद्यतित रखने की आवश्यकता है, यदि यह प्रत्येक प्रविष्टि पर है, तो संग्रहित प्रक्रिया को कर्सर सम्मिलित घटना में कॉल करें। यदि यह एक घंटे का काम है, तो इसे चलाने के लिए एक घंटे का काम निर्धारित करें।

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

द्विआधारी प्रारूप में, यह समझाना आसान है। मान लें कि किसी आइटम को असाइन किए जाने वाले चार टैग हैं, बाइनरी में हम उस का प्रतिनिधित्व कर सकते हैं

0000

यदि सभी चार टैग किसी ऑब्जेक्ट को सौंपे जाते हैं, तो ऑब्जेक्ट इस तरह दिखेगा ...

1111

अगर सिर्फ पहले दो ...

1100

फिर यह आपके इच्छित कॉलम में 1s और शून्य के साथ द्विआधारी मूल्यों को खोजने का मामला है। SQL सर्वर के Bitwise ऑपरेटरों का उपयोग करके, आप यह देख सकते हैं कि पहले कॉलम में बहुत ही सरल प्रश्नों का उपयोग करके 1 है।

अधिक जानने के लिए इस लिंक को देखें ।


0

अन्य लोगों ने जो कहा है उसे समता करने के लिए: चाल स्कीमा में नहीं है , यह क्वेरी में है

Entities / Labels / Tags का भोली स्कीमा जाने का सही तरीका है। लेकिन जैसा कि आपने देखा है, यह तुरंत स्पष्ट नहीं है कि बहुत सारे टैग के साथ AND क्वेरी कैसे करें।

उस क्वेरी को ऑप्टिमाइज़ करने का सबसे अच्छा तरीका प्लेटफ़ॉर्म-आश्रित होगा, इसलिए मैं आपके RDBS के साथ आपके प्रश्न को फिर से टैग करने और "कुछ करने के लिए इष्टतम तरीका और एक टैगिंग डेटाबेस पर क्वेरी करने के लिए" शीर्षक बदलने की सलाह दूंगा।

मेरे पास एमएस एसक्यूएल के लिए कुछ सुझाव हैं, लेकिन यदि आप जिस प्लेटफॉर्म का उपयोग कर रहे हैं वह नहीं होगा।


6
आप शायद एक निश्चित तकनीक के बारे में tidbits देने से बचना चाहिए क्योंकि इस समस्या डोमेन में काम करने की कोशिश कर रहे अन्य लोग वास्तव में उस तकनीक का उपयोग कर रहे होंगे और लाभान्वित होंगे।
ब्रायन रेहबीन

0

उपरोक्त उत्तर के लिए भिन्नता टैग आईडी लेती है, उन्हें क्रमबद्ध करती है, एक ^ अलग स्ट्रिंग के रूप में जोड़ती है और उन्हें हैश करती है। तो बस हैश को आइटम के साथ जोड़ दें। टैग का प्रत्येक संयोजन एक नई कुंजी बनाता है। AND खोज करने के लिए बस दिए गए टैग आईडी और खोज के साथ हैश बनाएं। किसी आइटम पर टैग बदलने से हैश को फिर से बनाया जा सकेगा। टैग के एक ही सेट के साथ आइटम एक ही हैश कुंजी साझा करते हैं।


4
इस दृष्टिकोण के साथ आप केवल टैग के एक ही सेट के साथ प्रविष्टियों की खोज कर सकते हैं - यह हमेशा मामूली है। अपने मूल प्रश्न में, मैं ऐसी प्रविष्टियाँ खोजना चाहता हूँ जिनके सभी टैग मेरे लिए क्वेरी हों, और संभवतः अधिक।
क्रिश्चियन बर्ग

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