Wie würden Sie eine Datenbank entwerfen, die die folgenden Tagging-Funktionen unterstützt:
- Elemente können eine große Anzahl von Tags haben
- Die Suche nach allen Elementen, die mit einem bestimmten Satz von Tags versehen sind, muss schnell erfolgen (die Elemente müssen ALLE Tags enthalten, es handelt sich also um eine UND-Suche, nicht um eine ODER-Suche).
- Das Erstellen / Schreiben von Elementen kann langsamer sein, um ein schnelles Nachschlagen / Lesen zu ermöglichen
Idealerweise sollte die Suche aller Elemente, die mit (mindestens) einer Menge von n angegebenen Tags versehen sind, mit einer einzigen SQL-Anweisung durchgeführt werden. Da die Anzahl der zu suchenden Tags sowie die Anzahl der Tags für ein Element unbekannt sind und möglicherweise hoch sind, ist die Verwendung von JOINs unpraktisch.
Irgendwelche Ideen?
Vielen Dank für alle bisherigen Antworten.
Wenn ich mich jedoch nicht irre, zeigen die angegebenen Antworten, wie eine ODER-Suche nach Tags durchgeführt wird. (Wählen Sie alle Elemente mit einem oder mehreren von n Tags aus.) Ich suche eine effiziente UND-Suche. (Wählen Sie alle Elemente mit ALL n Tags aus - und möglicherweise mehr.)
quelle
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)
sollte in Ordnung sein und skalieren, vorausgesetzt, die richtigen B-Tree-Indizes sind in der mittleren Tabelle vorhandenHier ist ein guter Artikel zum Kennzeichnen von Datenbankschemata:
http://howto.philippkeller.com/2005/04/24/Tags-Database-schemas/
zusammen mit Leistungstests:
http://howto.philippkeller.com/2005/06/19/Tagsystems-performance-tests/
Beachten Sie, dass die Schlussfolgerungen dort sehr spezifisch für MySQL sind, das (zumindest 2005 zum Zeitpunkt der Erstellung) sehr schlechte Volltextindizierungseigenschaften aufwies.
quelle
Ich sehe kein Problem mit einer einfachen Lösung: Tabelle für Elemente, Tabelle für Tags, Crosstable für "Tagging"
Indizes auf Kreuztabelle sollten ausreichend optimiert sein. Auswahl geeigneter Elemente wäre
UND Tagging wäre
Das ist zugegebenermaßen nicht so effizient für eine große Anzahl von Vergleichstags. Wenn Sie die Anzahl der Tags im Speicher beibehalten möchten, können Sie eine Abfrage durchführen, um mit Tags zu beginnen, die nicht häufig vorkommen, sodass die AND-Sequenz schneller ausgewertet wird. Abhängig von der erwarteten Anzahl der Tags, mit denen abgeglichen werden soll, und der Erwartung, dass sie mit einem einzelnen übereinstimmen, könnte dies eine OK-Lösung sein. Wenn Sie 20 Tags abgleichen und erwarten, dass ein zufälliges Element mit 15 von ihnen übereinstimmt, ist dies immer noch schwer in einer Datenbank.
quelle
Ich wollte nur hervorheben, dass der Artikel, auf den @Jeff Atwood verweist ( http://howto.philippkeller.com/2005/04/24/Tags-Database-schemas/ ), sehr gründlich ist (er beschreibt die Vorzüge von 3 verschiedenen Schemata Ansätze) und hat eine gute Lösung für die UND-Abfragen, die normalerweise eine bessere Leistung erbringen als die bisher hier erwähnten (dh es wird nicht für jeden Begriff eine korrelierte Unterabfrage verwendet). Auch viele gute Sachen in den Kommentaren.
ps - Der Ansatz, über den hier alle sprechen, wird im Artikel als "Toxi" -Lösung bezeichnet.
quelle
Möglicherweise möchten Sie mit einer nicht streng datenbankbezogenen Lösung wie einer Java Content Repository- Implementierung (z. B. Apache Jackrabbit ) experimentieren und eine darauf aufbauende Suchmaschine wie Apache Lucene verwenden .
Diese Lösung mit den geeigneten Caching-Mechanismen würde möglicherweise eine bessere Leistung liefern als eine selbst entwickelte Lösung.
Ich glaube jedoch nicht, dass Sie in einer kleinen oder mittleren Anwendung eine komplexere Implementierung benötigen würden als die in früheren Beiträgen erwähnte normalisierte Datenbank.
BEARBEITEN: Mit Ihrer Klarstellung scheint es zwingender, eine JCR-ähnliche Lösung mit einer Suchmaschine zu verwenden. Das würde Ihre Programme auf lange Sicht erheblich vereinfachen.
quelle
Am einfachsten ist es, eine Tags- Tabelle zu erstellen .
Target_Type
- für den Fall, dass Sie mehrere Tabellen markierenTarget
- Der Schlüssel für den zuTag
markierenden Datensatz - Der Text eines TagsDas Abfragen der Daten wäre ungefähr so:
UPDATE
Basierend auf Ihrer Anforderung an AND und den Bedingungen würde sich die obige Abfrage in etwa so verwandeln
quelle
Ich würde @Zizzencs Vorschlag unterstützen, dass Sie etwas wollen, das nicht vollständig (R) DB-zentriert ist
Irgendwie glaube ich, dass die Verwendung von einfachen nvarchar-Feldern zum Speichern dieser Tags mit einer ordnungsgemäßen Zwischenspeicherung / Indizierung zu schnelleren Ergebnissen führen kann. Aber das bin nur ich.
Ich habe zuvor Tagging-Systeme mit 3 Tabellen implementiert, um eine Viele-zu-Viele-Beziehung darzustellen (Item Tags ItemTags), aber ich nehme an, Sie werden sich an vielen Stellen mit Tags befassen. Ich kann Ihnen sagen, dass 3 Tabellen erforderlich sind Wenn Sie die ganze Zeit gleichzeitig manipuliert / abgefragt werden, wird Ihr Code definitiv komplexer.
Vielleicht möchten Sie überlegen, ob sich die zusätzliche Komplexität lohnt.
quelle
Sie können Verknüpfungen nicht vermeiden und sind dennoch etwas normalisiert.
Mein Ansatz ist es, eine Tag-Tabelle zu haben.
Dann haben Sie eine TagXREFID-Spalte in Ihrer Artikeltabelle.
Diese TagXREFID-Spalte ist eine FK für eine dritte Tabelle. Ich werde sie TagXREF nennen:
Alle Tags für einen Artikel zu erhalten, wäre ungefähr so:
Und um alle Elemente für ein Tag zu erhalten, würde ich Folgendes verwenden:
Um eine Reihe von Tags UND zu verknüpfen, müssen Sie die obige Anweisung geringfügig ändern, um AND-Tags hinzuzufügen.TagName = @ TagName1 AND Tags.TagName = @ TagName2 usw. und die Abfrage dynamisch erstellen.
quelle
Was ich gerne mache, ist eine Reihe von Tabellen, die die Rohdaten darstellen. In diesem Fall hätten Sie also
Dies funktioniert schnell für die Schreibzeiten und hält alles normal, aber Sie können auch beachten, dass Sie für jedes Tag zweimal Tabellen für jedes weitere Tag verknüpfen müssen, das Sie UND möchten, damit es langsam gelesen wird.
Eine Lösung zur Verbesserung des Lesens besteht darin, auf Befehl eine Caching-Tabelle zu erstellen, indem eine gespeicherte Prozedur eingerichtet wird, die im Wesentlichen eine neue Tabelle erstellt, die die Daten in einem reduzierten Format darstellt ...
Anschließend können Sie überlegen, wie oft die Tabelle mit markierten Elementen auf dem neuesten Stand gehalten werden muss. Wenn sie sich bei jeder Einfügung befindet, rufen Sie die gespeicherte Prozedur in einem Cursor-Einfügeereignis auf. Wenn es sich um eine stündliche Aufgabe handelt, richten Sie einen stündlichen Job ein, um sie auszuführen.
Um das Abrufen von Daten wirklich clever zu gestalten, sollten Sie eine gespeicherte Prozedur erstellen, um Daten aus den Tags abzurufen. Anstatt verschachtelte Abfragen in einer massiven case-Anweisung zu verwenden, möchten Sie einen einzelnen Parameter übergeben, der eine Liste von Tags enthält, die Sie aus der Datenbank auswählen möchten, und einen Datensatzsatz von Elementen zurückgeben. Dies ist am besten im Binärformat mit bitweisen Operatoren.
Im Binärformat ist es leicht zu erklären. Angenommen, einem Element müssen vier Tags zugewiesen werden. In Binärform könnten wir dies darstellen
Wenn alle vier Tags einem Objekt zugewiesen sind, sieht das Objekt folgendermaßen aus ...
Wenn nur die ersten beiden ...
Dann müssen Sie nur noch die Binärwerte mit den Einsen und Nullen in der gewünschten Spalte finden. Mit den Bitwise-Operatoren von SQL Server können Sie mithilfe sehr einfacher Abfragen überprüfen, ob in der ersten Spalte eine 1 steht.
Überprüfen Sie diesen Link, um mehr zu erfahren .
quelle
Um zu paraphrasieren, was andere gesagt haben: Der Trick ist nicht im Schema , sondern in der Abfrage .
Das naive Schema von Entities / Labels / Tags ist der richtige Weg. Wie Sie gesehen haben, ist jedoch nicht sofort klar, wie eine UND-Abfrage mit vielen Tags ausgeführt werden soll.
Der beste Weg, um diese Abfrage zu optimieren, ist plattformabhängig. Ich würde daher empfehlen, Ihre Frage erneut mit Ihrem RDBS zu kennzeichnen und den Titel in "Optimale Methode zum Ausführen einer UND-Abfrage in einer Kennzeichnungsdatenbank" zu ändern.
Ich habe ein paar Vorschläge für MS SQL, werde aber darauf verzichten, falls dies nicht die Plattform ist, die Sie verwenden.
quelle
Eine Variation der obigen Antwort besteht darin, die Tag-IDs zu nehmen, zu sortieren, als ^ getrennte Zeichenfolge zu kombinieren und sie zu hashen. Verknüpfen Sie dann einfach den Hash mit dem Element. Jede Kombination von Tags erzeugt einen neuen Schlüssel. Um eine UND-Suche durchzuführen, erstellen Sie einfach den Hash mit den angegebenen Tag-IDs neu und suchen Sie. Durch Ändern von Tags für ein Element wird der Hash neu erstellt. Elemente mit demselben Tag-Satz haben denselben Hash-Schlüssel.
quelle
Wenn Sie einen Array-Typ haben, können Sie die erforderlichen Daten vorab aggregieren. Siehe diese Antwort in einem separaten Thread:
Was ist der Nutzen des Array-Typs?
quelle