2008-08-21 4 views
244

Ich habe von ein paar Möglichkeiten zur Implementierung von Tagging gehört; Verwenden einer Mapping-Tabelle zwischen TagID und ItemID (macht Sinn für mich, aber skaliert?), Hinzufügen einer festen Anzahl von möglichen TagID-Spalten zu ItemID (scheint eine schlechte Idee), Halten von Tags in einer Textspalte, die durch Kommas getrennt ist (Sounds verrückt aber könnte funktionieren). Ich habe sogar gehört, dass jemand eine dünne Matrix empfiehlt, aber wie wachsen dann die Tag-Namen?Empfohlene SQL-Datenbank-Design für Tags oder Tagging

Fehle ich eine Best Practice für Tags?

+7

Okay das ist Frage # 20856, die (fast) gleiche Frage wird # 48475 mindestens zwei Wochen nach dieser Frage gestellt. – dlamblin

+6

Eine weitere interessante Frage ist "Wie implementiert SO Tags?" – Mostafa

+1

Eine andere interessante Frage ist "Würden Sie sie internationalisieren, und wenn ja, wie?" – DanMan

Antwort

353

Drei Tabellen (eine für die Speicherung aller Elemente, eine für alle Tags und eine für die Beziehung zwischen den beiden), richtig indiziert, mit Fremdschlüsseln, die auf einer geeigneten Datenbank laufen, sollten gut funktionieren und richtig skalieren.

+10

Ich glaube nicht, dass dies genug aufgeräumt werden kann. Dies ist eindeutig der beste Weg, dies zu tun. – BobbyShaftoe

+98

Klar? Wo ist der Beweis dafür, dass dies eindeutig der beste Weg ist, dies zu tun (außer für die Tatsache, dass es normalisiert ist - auch, erinnern Sie sich, Normalisierung ist schnelle Einsätze, langsame wählt). –

+0

Haben Sie eine Dokumentation zu diesem Ansatz? Ich glaube, das wäre auch mit Indizes statt der durch Komma getrennten Textspalte – Cesar

7

Ich habe immer die Tags in einer separaten Tabelle gehalten und hatte dann eine Zuordnungstabelle. Natürlich habe ich auch noch nie etwas wirklich Großes gemacht.

Mit einer "Tags" -Tabelle und einer Map-Tabelle ist es ziemlich trivial, Tag Clouds & zu generieren, da Sie SQL einfach zusammenstellen können, um eine Liste von Tags mit Zählungen zu erhalten, wie oft jedes Tag verwendet wird.

+1

Dies ist noch einfacher, wenn Sie keine Mapping-Tabelle verwenden:) – Scheintod

11

Verwenden Sie eine einzelne formatierte Textspalte [1] zum Speichern der Tags und verwenden Sie eine leistungsfähige Volltextsuchmaschine, um dies zu indexieren. Sonst werden Sie Skalierungsprobleme beim Booleschen Abfragen bekommen.

Wenn Sie Details zu den vorhandenen Tags benötigen, können Sie diese entweder in einer inkrementell gepflegten Tabelle verfolgen oder einen Stapeljob ausführen, um die Informationen zu extrahieren.

[1] Einige RDBMS bieten sogar einen nativen Array-Typ, der möglicherweise besser für die Speicherung geeignet ist, da er keinen Parsing-Schritt benötigt, aber Probleme bei der Volltextsuche verursachen könnte.

+0

Kennen Sie eine Volltext-Suchmaschine, die keine Variationen für ein Wort findet? Zum Beispiel gibt die Suche nach Büchern Bücher zurück? Was machen Sie auch mit Tags wie "C++"? SQL Server würde beispielsweise die Pluszeichen im Index entfernen. Vielen Dank. –

+0

Probieren Sie Sphinx - http://sphinxsearch.com – oyatek

+0

Dieses 3-teilige Tutorial ist vielleicht nützlich für diejenigen, die diese Route gehen (Volltextsuche). Es verwendet PostgreSQL native Funktionen: http://shisaa.jp/postset/postgresql-full-text-search-part-1.html – Will

37

Wenn Sie eine Datenbank verwenden, die Map-Reduce unterstützt, wie Couchdb, ist das Speichern von Tags in einem einfachen Textfeld oder Listenfeld in der Tat der beste Weg. Beispiel:

tagcloud: { 
    map: function(doc){ 
    for(tag in doc.tags){ 
     emit(doc.tags[tag],1) 
    } 
    } 
    reduce: function(keys,values){ 
    return values.length 
    } 
} 

das Lauf mit Gruppe = true Willen Gruppe die Ergebnisse von Tag-Namen und sogar eine Zählung der Anzahl der Male zurückkehren, dass Tag aufgetreten. Es ist sehr ähnlich zu counting the occurrences of a word in text.

+4

+1 Schön, einige NoSQL-Implementierungen zu sehen. – Xeoncross

+0

@NickRetallack Der Link funktioniert nicht. Wenn Sie könnten, aktualisieren Sie diese Antwort. – xralf

+0

Ok Ich ersetzte den Link durch einen auf archive.org –

57

Normalerweise würde ich mit Yaakov Ellis zustimmen, aber in diesem speziellen Fall gibt es eine andere praktikable Lösung:

Verwenden Sie zwei Tabellen:

Table: Item 
Columns: ItemID, Title, Content 
Indexes: ItemID 

Table: Tag 
Columns: ItemID, Title 
Indexes: ItemId, Title 

Dieser einige wichtige Vorteile:

Zuerst macht es Entwicklung viel einfacher: in der Drei-Tabellen-Lösung für Einfügen und Update von item müssen Sie die Tag Tabelle nachsehen, ob es bereits Einträge gibt. Dann müssen Sie sie mit neuen verbinden. Dies ist keine triviale Aufgabe.

Dann macht Abfragen einfacher (und vielleicht schneller). Es gibt drei wichtige Datenbankabfragen, die Sie ausführen werden: Geben Sie alle Tags für eine Item aus, zeichnen Sie eine Tag-Cloud und wählen Sie alle Elemente für einen Tag-Titel aus.

Alle Schlagworte für ein Item:

3-Table:

SELECT Tag.Title 
    FROM Tag 
    JOIN ItemTag ON Tag.TagID = ItemTag.TagID 
WHERE ItemTag.ItemID = :id 

2-Table:

SELECT Tag.Title 
FROM Tag 
WHERE Tag.ItemID = :id 

Tag-Cloud:

3- Tabelle:

SELECT Tag.Title, count(*) 
    FROM Tag 
    JOIN ItemTag ON Tag.TagID = ItemTag.TagID 
GROUP BY Tag.Title 

2-Table:

SELECT Tag.Title, count(*) 
    FROM Tag 
GROUP BY Tag.Title 

Angebote für einen Tag:

3-Table:

SELECT Item.* 
    FROM Item 
    JOIN ItemTag ON Item.ItemID = ItemTag.ItemID 
    JOIN Tag ON ItemTag.TagID = Tag.TagID 
WHERE Tag.Title = :title 

2-Table:

SELECT Item.* 
    FROM Item 
    JOIN Tag ON Item.ItemID = Tag.ItemID 
WHERE Tag.Title = :title 

Aber es gibt auch einige Nachteile: Es könnte mehr Platz in der Datenbank benötigen (was zu mehr Festplattenoperationen führen könnte, was langsamer ist) und es ist nicht normalisiert, was zu Inkonsistenzen führen könnte.

Die Größe Argument ist nicht so stark, weil die eigentliche Natur der Tags ist, dass sie normalerweise ziemlich klein sind, so dass die Größenzunahme nicht groß ist. Man könnte argumentieren, dass die Abfrage nach dem Tag-Titel in einer kleinen Tabelle, die jedes Tag nur einmal enthält, viel schneller ist, und dies ist sicherlich wahr. Aber die Einsparungen zu berücksichtigen, weil man nicht beitreten muss, und die Tatsache, dass man einen guten Index dafür aufbauen kann, könnten dies leicht kompensieren. Dies hängt natürlich stark von der Größe der Datenbank ab, die Sie verwenden.

Das Inkonsistenzargument ist auch ein wenig unklar. Tags sind freie Textfelder und es gibt keine zu erwartende Operation wie 'alle Tags umbenennen "foo" in "bar"'.

Also tldr: Ich würde für die Zwei-Tabellen-Lösung gehen. (. In der Tat, ich werde fand ich diesen Artikel zu sehen, ob es gültige Argumente dagegen.)

+0

Bedeutet "Index: ItemId, Title" einen Index für jeden oder einen Index, der beides enthält? – DanMan

+0

Normalerweise zwei Indizes. Kann jedoch von der verwendeten Datenbank abhängen. – Scheintod

+1

In der Tag-Tabelle ist ItemId und Tag einen zusammengesetzten Schlüssel? oder hast du auch einen PK? – Rippo

0

Ich würde vorschlagen, folgende Konstruktion: Artikeltabelle: Itemid, taglist1, taglist2
dies wird schnell sein und einfach speichern und abrufen der Daten auf Artikelebene.

Parallel bauen eine andere Tabelle: Schlagwörter tag nicht Tag eindeutige Kennung machen, und wenn Sie in der 2. Spalte der Platz nicht ausreicht, die können sagen, enthält 100 Elemente eine weitere Zeile erstellen.

Jetzt während der Suche nach Elementen für ein Tag wird es super schnell sein.

+0

https://en.wikipedia.org/wiki/First_normal_form ausgeführt werden, obwohl es Ausnahmen zu diesem gibt, können Sie denormalize, aber nicht hier – Dheeraj