Design di database SQL consigliato per tag o tagging

Ho sentito di alcuni modi per implementare il tagging; usando una tabella di mapping tra TagID e ItemID (ha senso per me, ma scala?), aggiungendo un numero fisso di possibili colonne TagID a ItemID (sembra una ctriggers idea), Mantenendo i tag in una colonna di testo separata da virgole (suoni pazzo ma potrebbe funzionare). Ho persino sentito qualcuno consigliare una matrice sparsa, ma come si sviluppano i nomi dei tag con grazia?

Mi manca una buona pratica per i tag?

Tre tabelle (una per la memorizzazione di tutti gli elementi, una per tutte le etichette e una per la relazione tra le due), opportunamente indicizzate, con chiavi esterne impostate su un database appropriato, dovrebbero funzionare correttamente e scalare correttamente.

Table: Item Columns: ItemID, Title, Content Table: Tag Columns: TagID, Title Table: ItemTag Columns: ItemID, TagID 

Normalmente sono d’accordo con Yaakov Ellis, ma in questo caso speciale c’è un’altra soluzione praticabile:

Utilizza due tabelle:

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

Questo ha alcuni importanti vantaggi:

Per prima cosa rende lo sviluppo molto più semplice: nella soluzione a tre tavoli per l’inserimento e l’aggiornamento item devi cercare la tabella Tag per vedere se ci sono già voci. Quindi devi unirti a loro con quelli nuovi. Questo non è un compito banale.

Quindi rende le query più semplici (e forse più veloci). Esistono tre principali query di database che dovrai eseguire: emettere tutti i Tags per un Item , disegnare un tag-cloud e selezionare tutti gli elementi per un titolo tag.

Tutti i tag per un articolo:

3-Table:

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

2-Tabella:

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

Tag-Cloud:

3-Table:

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

2-Tabella:

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

Articoli per un 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-Tabella:

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

Ma ci sono anche alcuni svantaggi: potrebbe richiedere più spazio nel database (che potrebbe portare a più operazioni del disco che è più lento) e non è normalizzato, il che potrebbe portare a incongruenze.

L’argomento delle dimensioni non è così forte perché la natura stessa dei tag è che sono normalmente piuttosto piccoli, quindi l’aumento delle dimensioni non è grande. Si potrebbe sostenere che la query per il titolo del tag è molto più veloce in una piccola tabella che contiene ogni tag solo una volta e questo è certamente vero. Ma prendere in considerazione i risparmi per non dover partecipare e il fatto che si può build un buon indice su di essi potrebbe facilmente compensare questo. Questo ovviamente dipende molto dalle dimensioni del database che stai utilizzando.

Anche l’argomento di incoerenza è un po ‘discutibile. I tag sono campi di testo liberi e non sono previste operazioni come “rinomina tutti i tag” pippo “su” barra “”.

Quindi tldr: vorrei andare per la soluzione a due tavoli. (In effetti sto andando a. Ho trovato questo articolo per vedere se ci sono argomenti validi contro di esso.)

Se stai usando un database che supporta map-reduce, come couchdb, la memorizzazione di tag in un campo di testo semplice o in un campo elenco è davvero il modo migliore. Esempio:

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

L’esecuzione di questo con group = true raggrupperà i risultati in base al nome del tag e persino restituirà un conteggio del numero di volte in cui è stato rilevato il tag. È molto simile al conteggio delle occorrenze di una parola nel testo .

Utilizzare una singola colonna di testo formattata [1] per memorizzare i tag e utilizzare un motore di ricerca full text capace per indicizzarlo. Altrimenti si verificheranno problemi di ridimensionamento quando si tenta di implementare query booleane.

Se hai bisogno di dettagli sui tag che hai, puoi tenerne traccia in una tabella gestita in modo incrementale o eseguire un lavoro batch per estrarre le informazioni.

[1] Alcuni RDBMS forniscono anche un tipo di array nativo che potrebbe essere ancora più adatto all’archiviazione non avendo bisogno di una fase di analisi, ma potrebbe causare problemi con la ricerca di testo completo.

Ho sempre tenuto i tag in una tabella separata e poi ho avuto una tabella di mapping. Naturalmente non ho mai fatto nulla su una scala molto grande.

Avere una tabella “tag” e una tabella delle mappe rende piuttosto banale la generazione di nuvole di tag e questo perché è ansible assemblare facilmente SQL per ottenere un elenco di tag con conteggi della frequenza con cui ogni tag viene utilizzato.

Suggerirei il seguente design: Item Table: Itemid, taglist1, taglist2
questo sarà veloce e renderà facile il salvataggio e il recupero dei dati a livello di articolo.

In parallelo costruisci un’altra tabella: i tag tag non rendono l’identificatore univoco del tag e se esaurisci lo spazio nella seconda colonna che contiene diciamo 100 elementi creano un’altra riga.

Ora mentre cerchi gli oggetti per un tag sarà super veloce.