سؤال

كنت أتساءل ما هي أفضل طريقة لتنفيذ نظام العلامات ، مثل النظام المستخدم في ذلك. كنت أفكر في هذا ولكن لا يمكنني التوصل إلى حل جيد قابل للتطوير.

كنت أفكر في الحصول على حل أساسي من الجدول 3: وجود أ tags الجدول ، و articles الجداول و tag_to_articles الطاولة.

هل هذا هو الحل الأفضل لهذه المشكلة ، أم أن هناك بدائل؟ باستخدام هذه الطريقة ، سيصبح الجدول كبيرًا للغاية في الوقت المناسب ، وللتفتيش هذا ليس فعالًا للغاية أفترض. من ناحية أخرى ، ليس من المهم أن ينفذ الاستعلام بسرعة.

هل كانت مفيدة؟

المحلول

أعتقد أنك ستجد مثيرة للاهتمام هذا المنشور المدونة: العلامات: مخططات قاعدة البيانات

المشكلة: تريد أن يكون لديك مخطط قاعدة بيانات حيث يمكنك وضع علامة مرجعية (أو منشور مدونة أو أي شيء آخر) مع العديد من العلامات التي تريدها. في وقت لاحق ، تريد تشغيل استفسارات لتقييد الإشارات المرجعية على اتحاد أو تقاطع العلامات. تريد أيضًا استبعاد (قل: ناقص) بعض العلامات من نتيجة البحث.

حل "mysqlicious"

في هذا الحل ، يحتوي المخطط على طاولة واحدة فقط ، فهو غير طبيعي. يسمى هذا النوع "الحل mysqlicious" لأن mysqlicious يستورد del.icio.us البيانات في جدول مع هذا الهيكل.

enter image description hereenter image description here

Quection (و) Query لـ "Search+WebService+Semweb":

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

Union (OR) Query لـ "Search | WebService | Semweb":

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

ناقص الاستعلام عن "Search+WebService-Semweb"

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

حل "scuttle"

يتسحب هربا بسرعه تنظم بياناتها في جدولين. هذا الجدول "Sccategories" هو "العلامة"-وقد حصل على مفتاح خارجي لـ "الإشارة المرجعية".

enter image description here

استفسار تقاطع (و) عن "إشارة مرجعية+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

أولاً ، يتم البحث في جميع مجموعات الإشارة المرجعية ، حيث تكون العلامة "إشارة مرجعية" أو "WebService" أو "Semweb" ( لقد حصلت على جميع العلامات الثلاثة التي تم البحث عنها في الاعتبار (بعد العد (B.Bid) = 3).

Union (OR) Query for "Bobmark | 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

Minus (الاستبعاد) استعلام لـ "Bookmark+WebService-Semweb" ، أي: الإشارة المرجعية و WebService وليس Semweb.

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

إن ترك العد يؤدي إلى الاستعلام عن "Bookmark | WebService-Semweb".


حل "toxi"

توكسي جاء مع هيكل ثلاثي الطاولة. عبر الجدول "tagmap" المرجعية والعلامات ذات الصلة بـ N إلى M. يمكن استخدام كل علامة مع إشارات مرجعية مختلفة والعكس صحيح. يستخدم هذا db-schema أيضًا بواسطة WordPress. الاستعلامات هي نفسها تمامًا كما في حل "scuttle".

enter image description here

استفسار تقاطع (و) عن "إشارة مرجعية+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

Union (OR) Query for "Bookmark | 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

Minus (الاستبعاد) استعلام لـ "Bookmark+WebService-Semweb" ، أي: الإشارة المرجعية و WebService وليس Semweb.

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

إن ترك العد يؤدي إلى الاستعلام عن "Bookmark | WebService-Semweb".

نصائح أخرى

لا حرج في الحل الثلاثة.

خيار آخر هو الحد من عدد العلامات التي يمكن تطبيقها على مقال (مثل 5 في SO) وإضافة تلك مباشرة إلى جدول المقالة الخاص بك.

إن تطبيع DB له فوائده وعيوبه ، تمامًا مثل الأشياء الشاقة في جدول واحد له فوائد وعيوب.

لا شيء يقول أنه لا يمكنك فعل كليهما. يتعارض مع نماذج DB العلائقية لتكرار المعلومات ، ولكن إذا كان الهدف هو الأداء ، فقد تضطر إلى كسر النماذج.

سيعمل تطبيق الجدول الثلاثة المقترح الخاص بك على وضع العلامات.

يستخدم مكدس الفائض ، ومع ذلك ، تنفيذ مختلف. يقومون بتخزين العلامات إلى عمود Varchar في جدول المنشورات في نص عادي ويستخدمون فهرسة النص الكامل لجلب المنشورات التي تتطابق مع العلامات. فمثلا posts.tags = "algorithm system tagging best-practices". أنا متأكد من أن جيف ذكر هذا في مكان ما ولكني نسيت أين.

الحل المقترح هو الأفضل-إذا لم يكن من الممكن أن أفكر في معالجة العلاقة بين العلامات والمقالات العديدة بين العلامات والمقالات. لذا فإن تصويتي هي "نعم ، لا يزال الأفضل". سأكون مهتمًا بأي بدائل.

إذا كانت قاعدة البيانات الخاصة بك تدعم المصفوفات القابلة للفهرسة (مثل postgresql ، على سبيل المثال) ، فإنني أوصي بحل غير طبيعي تمامًا - علامات المتجر كمجموعة من الأوتار على نفس الجدول. إذا لم يكن الأمر كذلك ، فإن كائنات تعيين الجدول الثانوي إلى العلامات هي الحل الأفضل. إذا كنت بحاجة إلى تخزين معلومات إضافية مقابل العلامات ، فيمكنك استخدام جدول علامات منفصل ، ولكن ليس هناك فائدة من تقديم انضمام ثانية لكل عملية بحث عن علامة.

I would like to suggest optimised MySQLicious for better performance. Before that the drawbacks of Toxi (3 table) solution is

If you have millions of questions, and it has 5 tags in each, then there will be 5 million entries in tagmap table. So first we have to filter out 10 thousand tagmap entries based on tag search then again filter out matching questions of those 10 thousand. So while filtering out if the artical id is simple numeric then it is ok, but if it is kind of UUID (32 varchar) then filtering out needs larger comparison though it is indexed.

My solution:

Whenever new tag is created, have counter++ (base 10), and convert that counter into base64. Now each tag name will have base64 id. and pass this id to UI along with name. This way you will be having maximum of two char id till we have 4095 tags created in our system. Now concatenate these multiple tags into each question table tag column. Add delimiter as well and make it sorted.

So table looks like this

enter image description here

While querying, query on id instead of real tag name. Since it is SORTED, and condition on tag will be more efficient (LIKE '%|a|%|c|%|f|%).

Note that single space delimiter is not enough and we need double delimiter to differentiate tags like sql and mysql because LIKE "%sql%" will return mysql results as well. Should be LIKE "%|sql|%"

I know the search is non indexed but still you might have indexed on other columns related to article like author/dateTime else will lead to full table scan.

Finally with this solution, no inner join required where million records have to be compared with 5 millions records on join condition.

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

Notes:

  • This is better than TOXI in that it does not go through an extra many:many table which makes optimization difficult.
  • Sure, my approach may be slightly more bulky (than TOXI) due to the redundant tags, but that is a small percentage of the whole database, and the performance improvements may be significant.
  • It is highly scalable.
  • It does not have (because it does not need) a surrogate AUTO_INCREMENT PK. Hence, it is better than Scuttle.
  • MySQLicious sucks because it cannot use an index (LIKE with leading wild card; false hits on substrings)
  • For MySQL, be sure to use ENGINE=InnoDB in order to get 'clustering' effects.

Related discussions (for MySQL):
many:many mapping table optimization
ordered lists

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top