94 votes

Comment mettre en place un système de tag

Je me demandais quelle est la meilleure façon de mettre en oeuvre un système de tag, comme celui utilisé sur. Je pensais à cela, mais je ne peux pas trouver une bonne solution évolutive.

Je pensais avoir une base de 3 table de la solution: avoir un tags tableau, articles tables et un tag_to_articles table.

Est-ce la meilleure solution à ce problème, ou y at-il des alternatives? L'utilisation de cette méthode de la table ne peuvent être extrêmement grande dans le temps, et pour la recherche, ce n'est pas trop efficace je l'assume. D'autre part, il n'est pas aussi importante que la requête s'exécute rapidement.

123voto

Nick Dandoulakis Points 26809

Je crois que vous trouverez intéressant ce blog: Tags: schémas de Base de données

Le Problème: Vous voulez avoir un schéma de base de données où vous pouvez marquer un signet (ou un post de blog ou autre) avec autant de tags que vous le souhaitez. Par la suite, vous souhaitez exécuter des requêtes pour contraindre les signets pour un l'union ou l'intersection de balises. Vous aussi vous voulez exclure (dire: moins) certaines balises à partir du résultat de recherche.

"MySQLicious" solution

Dans cette solution, le schéma a obtenu un tableau, il est dénormalisé. Ce type est appelé "MySQLicious solution" parce que MySQLicious importations del.icio.nous les données dans une table avec cette structure.

enter image description hereenter image description here

Intersection (ET) Requête pour la recherche "de+service+semweb":

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

De l'Union (OU) Requête pour "search|webservice|semweb":

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

Moins Requête pour la recherche "de+webservice-semweb"

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

"Saborder" solution

Scuttle organise ses données dans deux tables. Cette table "scCategories" est le "tag"-table et a une clé étrangère à la "signet"-table.

enter image description here

Intersection (ET) Requête pour "signet+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

Tout d'abord, tous les signets-tag combinaisons sont recherchées, où la balise est "signet", "webservice" ou "semweb" (c.catégorie ('bookmark', 'webservice', 'semweb')), puis il suffit de les signets qui ont eu tous les trois balises recherchés sont pris en compte (AYANT le compte b.bId)=3).

De l'Union (OU) Requête pour "signet|webservice|semweb": Il suffit de laisser la clause HAVING et vous avez de l'union:

SELECT b.*
FROM scBookmarks b, scCategories c
WHERE c.bId = b.bId
AND (c.category IN ('bookmark', 'webservice', 'semweb'))
GROUP BY b.bId

Moins (Exclusion) Requête pour "signet+webservice-semweb", c'est: signet ET webservice ET PAS 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

En laissant de côté les AYANT COMTE mène à la Requête de "signet|webservice-semweb".


"Toxi" solution

Toxi est venu avec un trois-structure de la table. Via la table "tagmap" les signets et les tags sont des n-m connexes. Chaque balise peut être utilisée avec différents signets et vice versa. Ce DB-schéma est également utilisé par wordpress. Les requêtes sont tout à fait le même que dans le "saborder" solution.

enter image description here

Intersection (ET) Requête pour "signet+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

De l'Union (OU) Requête pour "signet|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

Moins (Exclusion) Requête pour "signet+webservice-semweb", c'est: signet ET webservice ET PAS 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

En laissant de côté les AYANT COMTE mène à la Requête de "signet|webservice-semweb".

8voto

John Points 12438

Rien de mal avec votre trois-tableau de la solution.

Une autre option est de limiter le nombre de balises qui peuvent être appliqués à un objet (comme 5 dans) et de les ajouter directement à votre article table.

La normalisation de la DB a ses avantages et ses inconvénients, tout comme le câblage de choses dans un tableau a des avantages et des inconvénients.

Rien ne dit que vous ne pouvez pas faire les deux. Il va à l'encontre de relationnel paradigmes de répéter les informations, mais si l'objectif est la performance que vous pouvez avoir à briser les paradigmes.

6voto

Juha Syrjälä Points 11475

L'implémentation que vous proposez avec trois tables fonctionnera pour le marquage.

Le débordement de pile utilise cependant une implémentation différente. Ils stockent les balises dans la colonne varchar de la table posts en texte brut et utilisent l'indexation de texte intégral pour récupérer les publications qui correspondent aux balises. Par exemple posts.tags = "algorithm system tagging best-practices" . Je suis sûr que Jeff en a déjà parlé quelque part, mais j'oublie où.

3voto

David Thomas Points 111253

La solution proposée est la meilleure solution, si ce n’est la seule possible, à laquelle je puisse penser pour traiter la relation multiple entre étiquettes et articles. Donc, mon vote est «oui, c'est toujours le meilleur». Je serais intéressé par toute alternative cependant.

2voto

Nick Johnson Points 79909

Si votre base de données prend en charge les tableaux indexables (tels que PostgreSQL, par exemple), je vous recommanderais une solution entièrement dénormalisée: des balises de type store stockées sous forme de tableau de chaînes sur la même table. Sinon, une table secondaire mappant des objets sur des balises est la meilleure solution. Si vous devez stocker des informations supplémentaires sur les balises, vous pouvez utiliser une table de balises distincte, mais il est inutile d'introduire une seconde jointure pour chaque recherche de balise.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X