سؤال

كيف يمكنك تصميم قاعدة بيانات لدعم ميزات وضع العلامات التالية:

  • يمكن أن تحتوي العناصر على عدد كبير من العلامات
  • يجب أن تكون عمليات البحث عن جميع العناصر التي تم وضع علامة عليها بمجموعة معينة من العلامات سريعة (يجب أن تحتوي العناصر على جميع العلامات، لذا فهي عبارة عن بحث AND، وليس بحث OR)
  • قد يكون إنشاء/كتابة العناصر أبطأ لتمكين البحث/القراءة السريعة

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

أيه أفكار؟


شكرا على جميع الاجابات حتى الآن.

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

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

المحلول

حول أندينغ:يبدو أنك تبحث عن عملية "التقسيم العلائقي". هذا المقال يغطي تقسيم العلائقية بطريقة موجزة ومفهومة.

حول الأداء:يبدو النهج القائم على الصورة النقطية بديهيًا أنه يناسب الموقف جيدًا.ومع ذلك، لست مقتنعًا بأنه من الجيد تنفيذ فهرسة الصور النقطية "يدويًا"، كما يقترح digiguru:يبدو الأمر وكأنه موقف معقد عند إضافة علامات جديدة (؟) لكن بعض أنظمة إدارة قواعد البيانات (بما في ذلك Oracle) تقدم فهارس صور نقطية قد تكون مفيدة بطريقة ما، لأن نظام الفهرسة المدمج يتخلص من التعقيد المحتمل لصيانة الفهرس؛بالإضافة إلى ذلك، يجب أن يكون نظام إدارة قواعد البيانات (DBMS) الذي يقدم فهارس الصور النقطية قادرًا على أخذها في الاعتبار بشكل مناسب عند تنفيذ خطة الاستعلام.

نصائح أخرى

إليك مقالة جيدة حول وضع علامات على مخططات قاعدة البيانات:

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

بالإضافة إلى اختبارات الأداء:

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

لاحظ أن الاستنتاجات هناك خاصة جدًا بـ MySQL، والتي (على الأقل في عام 2005 في وقت كتابة هذا المقال) كانت ذات خصائص فهرسة نص كامل سيئة للغاية.

لا أرى مشكلة في الحل المباشر:جدول للعناصر، جدول للعلامات، جدول تبادلي لـ "وضع العلامات"

يجب أن تكون المؤشرات الموجودة على الطاولة المتقاطعة بمثابة تحسين كافٍ.اختيار العناصر المناسبة سيكون

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 ...

ومن المسلم به أنه ليس فعالاً بالنسبة لعدد كبير من علامات المقارنة.إذا كنت ترغب في الحفاظ على عدد العلامات في الذاكرة، فيمكنك إجراء استعلام يبدأ بعلامات غير متكررة، لذلك سيتم تقييم التسلسل AND بشكل أسرع.اعتمادًا على العدد المتوقع من العلامات التي سيتم مطابقتها وتوقع مطابقة أي واحدة منها، قد يكون هذا حلاً جيدًا، إذا كنت تريد مطابقة 20 علامة، وتتوقع أن يتطابق بعض العناصر العشوائية مع 15 منها، فسيظل هذا ثقيلًا على قاعدة بيانات.

أردت فقط تسليط الضوء على المقالة التي يرتبط بها @Jeff Atwood (http://howto.philippkeller.com/2005/04/24/Tags-Database-schemas/) شامل للغاية (يناقش مزايا 3 طرق مختلفة للمخطط) ولديه حل جيد لاستعلامات AND التي عادةً ما تؤدي أداءً أفضل مما تم ذكره هنا حتى الآن (أي.ولا يستخدم استعلامًا فرعيًا مرتبطًا لكل مصطلح).أيضا الكثير من الأشياء الجيدة في التعليقات.

ملاحظة - يُشار إلى النهج الذي يتحدث عنه الجميع هنا باسم الحل "Toxi" في المقالة.

قد ترغب في تجربة حل غير متعلق بقاعدة البيانات مثل مستودع محتوى جافا التنفيذ (على سبيل المثال أباتشي جاكرابت) واستخدم محرك بحث مبنيًا على ذلك مثل أباتشي لوسين.

من المحتمل أن يؤدي هذا الحل مع آليات التخزين المؤقت المناسبة إلى أداء أفضل من الحلول المحلية.

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

يحرر:مع توضيحك، يبدو أكثر إلحاحًا استخدام حل يشبه JCR مع محرك بحث.وهذا من شأنه أن يبسط برامجك إلى حد كبير على المدى الطويل.

أسهل طريقة هي إنشاء العلامات طاولة.
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]

أنا أؤيد اقتراحZizzencs الثاني بأنك قد ترغب في شيء لا يتمحور حول قاعدة بيانات (R) تمامًا

بطريقة ما، أعتقد أن استخدام حقول nvarchar العادية لتخزين تلك العلامات مع بعض التخزين المؤقت/الفهرسة المناسبة قد يؤدي إلى نتائج أسرع.ولكن هذا أنا فقط.

لقد قمت بتنفيذ أنظمة وضع العلامات باستخدام 3 جداول لتمثيل علاقة متعدد إلى متعدد من قبل (علامات العنصر ItemTags)، ولكن أفترض أنك ستتعامل مع العلامات في الكثير من الأماكن، يمكنني أن أخبرك أنه مع وجود 3 جداول يجب أن من المؤكد أن التلاعب/الاستعلام عنه في وقت واحد طوال الوقت سيجعل التعليمات البرمجية الخاصة بك أكثر تعقيدًا.

قد ترغب في التفكير فيما إذا كان التعقيد الإضافي يستحق ذلك.

لن تتمكن من تجنب عمليات الانضمام وسيظل بإمكانك التطبيع إلى حد ما.

أسلوبي هو الحصول على جدول العلامات.

 TagId (PK)| TagName (Indexed)

ثم، لديك عمود TagXREFID في جدول العناصر الخاص بك.

يعد عمود TagXREFID بمثابة 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;

ولمجموعة من العلامات معًا، يمكنك تعديل العبارة أعلاه قليلاً لإضافة AND TagName = @TagName1 AND TagName = @TagName2 وما إلى ذلك... وبناء الاستعلام ديناميكيًا.

ما أحب أن أفعله هو أن يكون لدي عدد من الجداول التي تمثل البيانات الأولية، لذا في هذه الحالة سيكون لديك

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

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

يتمثل أحد الحلول لتحسين القراءة في إنشاء جدول تخزين مؤقت بناءً على أمر عن طريق إعداد إجراء مخزن يقوم بشكل أساسي بإنشاء جدول جديد يمثل البيانات بتنسيق مسطح...

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

بعد ذلك، يمكنك التفكير في عدد المرات التي يجب فيها تحديث جدول العناصر ذات العلامات، وإذا كان ذلك موجودًا في كل إدراج، فقم باستدعاء الإجراء المخزن في حدث إدراج المؤشر.إذا كانت مهمة بالساعة، فقم بإعداد مهمة بالساعة لتشغيلها.

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

في التنسيق الثنائي، من السهل الشرح.لنفترض أن هناك أربع علامات يتم تخصيصها لعنصر ما، ويمكننا تمثيل ذلك بالنظام الثنائي

0000

إذا تم تعيين جميع العلامات الأربع لكائن ما، فسيبدو الكائن بهذا الشكل...

1111

لو فقط الأولين..

1100

بعد ذلك، يتعلق الأمر فقط بالعثور على القيم الثنائية التي تحتوي على الآحاد والأصفار في العمود الذي تريده.باستخدام عوامل تشغيل Bitwise الخاصة بـ SQL Server، يمكنك التحقق من وجود 1 في أول الأعمدة باستخدام استعلامات بسيطة جدًا.

تحقق من هذا الرابط لمعرفة ذلك أكثر.

لإعادة صياغة ما قاله الآخرون:الحيلة ليست في مخطط, ، إنه في استفسار.

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

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

لدي بعض الاقتراحات بشأن MS SQL، ولكنني سأمتنع عنها في حالة عدم استخدام النظام الأساسي الذي تستخدمه.

هناك اختلاف في الإجابة أعلاه وهو أخذ معرفات العلامات وفرزها ودمجها كسلسلة ^ منفصلة وتجزئتها.ثم قم ببساطة بربط التجزئة بالعنصر.تنتج كل مجموعة من العلامات مفتاحًا جديدًا.لإجراء بحث وبحث، ما عليك سوى إعادة إنشاء التجزئة باستخدام معرفات العلامات المحددة والبحث.سيؤدي تغيير العلامات على عنصر ما إلى إعادة إنشاء التجزئة.العناصر التي لها نفس مجموعة العلامات تشترك في نفس مفتاح التجزئة.

إذا كان لديك نوع مصفوفة، فيمكنك تجميع البيانات المطلوبة مسبقًا.راجع هذه الإجابة في موضوع منفصل:

ما فائدة نوع المصفوفة؟

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