2009-09-03 7 views
1

J'ai une base de données MySQL avec 3 tables:Comment trouver des tags complémentaires?

  1. Le tableau principal des enregistrements appelés "pistes" (comme dans la musique)
  2. Une table de balises appelés "tags"
  3. Une table de jointure pour les deux appelés "taggings"

La table des étiquettes est essentiellement une liste de genres, qui est prédéfinie. Une piste peut alors avoir 1 ou plusieurs tags (via la table de jointure).

L'idée est, que l'utilisateur cocher les genres (étiquettes) pour lequel il ou elle veut trouver des pistes. Mais j'aimerais aussi que l'interface reflète les balises qui ne sont plus «utiles», c'est-à-dire les balises qui sont complémentaires aux balises actuellement sélectionnées.

Editer: Ce que j'ai manqué, c'est que j'ai besoin de trouver des balises qui sont complémentaires à l'actuellement sélectionné des étiquettes. Voir mon commentaire ci-dessous. Exemple: l'utilisateur sélectionne les balises "rock" et "pop", et affiche une liste de pistes qui correspondent à "rock" + "pop". Mais supposons qu'il n'y ait pas de pistes dans la base de données qui aussi correspondent "jazz". Dans ce cas, j'aimerais désactiver la balise "jazz" dans l'interface, car "rock" + "pop" + "jazz" donnerait zéro résultat.

Existe-t-il une façon intelligente de faire cela avec MySQL?

+0

J'ai ajouté une autre option, c'est vraiment juste une reprise de la première, mais peut-être que cela ne va pas tuer votre client. – scottm

+0

Un ami a signalé quelque chose, ce qui complique énormément les choses: La requête devrait trouver des balises "consécutives", pour ainsi dire. C'est à dire. Si vous recherchez les tags 1 et/ou 3, vous trouverez des pistes qui ont l'un ou l'autre ou les deux. Jusqu'ici tout va bien. Mais les requêtes ci-dessous diront si les pistes ont tag 1 & X, _ ou tag 3 & X, mais ce qui est réellement nécessaire est de voir s'il y a des pistes qui ont des tags 1 _and_ 3 _and_ X. Et cela rend tout cela très difficile, comme je peux le dire – Flambino

Répondre

0

a fini par faire ceci:

  • Lorsqu'une piste est étiquetée, ses ID de balise sont concaténés (dans l'ordre) et ajouté à une table de recherche 1 colonnes (et bien sûr aussi des marquages). Par exemple. ", 1,2,4,6,9," est ajouté à la recherche (il y a une raison pour les virgules avant/arrière)
  • Lorsque les étiquettes sont sélectionnées lors de la recherche, elles sont concaténées de la même façon et utilisées dans un LIKE clause qui sélectionne tous les concaténations de la table de consultation contenant les ID tag
  • les concaténations trouvés sont ensuite traitées pour obtenir tous les ID qu'ils contiennent
  • Quelle que soit ID ne sont pas dans la liste qui en résultent sont donc complémentaires à ceux sélectionnés
1
select 
    tagid 
from 
    taggings 
where 
    trackid in ([list of, or subquery for your selected tracks]) 

Désactiver tous les tags, sauf si le résultat contient leur identifiant. Ou désactivez toutes les balises, puis réactivez celles qui sont renvoyées par cette requête. Vous pouvez également effectuer une restructuration et la convertir en une requête «in-in», mais cela serait normalement plus lent.

+0

Je pense que le point est d'avoir les contrôles activés et permettant à l'utilisateur de les cliquer. – scottm

+0

Eh bien, oui, l'utilisateur devrait être capable de cliquer sur les commandes de tag qui "ont du sens". Si la chose la plus efficace est de tout désactiver et d'en activer quelques-uns, ou de tout activer puis de désactiver certains, je ne sais pas. Cela dépend de la requête la plus efficace. Les balises de recherche sont utilisées avec les balises actuelles, ou trouvez celles qui ne sont pas utilisées avec celles en cours. – Flambino

+0

Les requêtes 'In-In' sont connues pour être inefficaces car elles nécessitent généralement une analyse complète de la table, alors que 'In' n'a besoin de rechercher que jusqu'au premier hit. 'Not in' est plus facile à lire et à comprendre, mais moins efficace. Comment vous gérez le traitement de ces données après la récupération, je ne peux pas dire sans en savoir plus sur la conception de votre interface. – krdluzni

0

Ceci est probablement pas le plus efficace:

SELECT 
    TagId --to disable 
FROM Tags 
WHERE TagId NOT IN(
    SELECT Distinct TagId FROM Taggings WHERE TrackId IN (
     SELECT TrackId FROM Taggings WHERE TagId in (1, 2) 
    ) 
) 
  1. Obtenez toutes les pistes correspondant à des balises sélectionnées.
  2. Prenez tous les tags assignés à ces pistes
  3. balises Désactiver pas dans cette liste

Modifier
Qu'en est-ce:

SELECT 
    DISTINCT TagId 
FROM 
    Taggings 
GROUP BY 
    TagId, 
    TrackId HAVING TrackId IN (
     SELECT 
      TrackId 
     FROM 
      Taggings 
     WHERE 
     TagId in (1, 2) 
    ) 

Cela devrait retourner tous les tags qui devrait être activé.

+0

Hmmm .. qui a crashé mon client MySQL :-) Le problème est, que j'ai des milliers de pistes, et j'ai besoin de l'interface pour être vraiment réactif. Bien que votre réponse fonctionnerait probablement, elle semble trop brute, pour ainsi dire. Je pense qu'il devrait être possible de trouver les tags_id qui sont utilisés ensemble, simplement à partir de la - short-list des balises sélectionnées, plutôt que d'une liste de milliers de track_ids. – Flambino

+0

Ouais, j'ai pensé que ça allait être un peu rude. Je ne pense pas que vous serez capable de le faire avec juste les étiquettes. Je pense que vous devez avoir les pistes pour savoir quelles sont les possibilités de tag restantes. – scottm

+0

Oui, vous avez probablement raison. Mais maintenant je pense à ajouter une autre table avec les différentes combinaisons d'étiquettes pour une recherche plus rapide. Je vais laisser cette question reposer ici pendant un moment et voir ce qui se passe. Mais merci pour la contribution jusqu'à présent! – Flambino

0

Avez-vous le contrôle sur la façon dont les balises sont ajoutées aux pistes? Si vous pouvez vous y intéresser, vous pouvez créer des métadonnées supplémentaires.

Essentiellement une jointure plusieurs-à-plusieurs entre les balises. Chaque fois que vous ajoutez un tag, vous ajoutez un enregistrement à cette table de jointure contenant une paire old-tag/new-tag (avec l'identifiant inférieur comme première valeur pour réduire la duplication), pour chacun des anciens tags de cette piste. IIRC, il existe un moyen de configurer la table pour ignorer les insertions en double, plutôt que de lancer des erreurs.Vous devrez également gérer cette table lors de la suppression des tags, ce qui prendra plus de temps, mais c'est probablement un événement rare.

Avec ce qui précède en place, vous avez une requête simple pour identifier les balises qui sont toujours d'actualité:

select 
    tag_a 
from 
    related_tags 
where 
    tag_b in ([tags_already_in_search]) 
union 
select 
    tag_b 
from 
    related_tags 
where 
    tag_a in([tags_already_in_search]) 

Cette solution se déplace essentiellement une partie du temps de traitement au point dans le temps où les balises sont ajoutés et supprimés.

+0

Intéressant! Je vais essayer ça. Et oui, je pensais à créer une table de consultation à deux colonnes exactement comme vous le décrivez, précisément parce que cela déplacerait la charge du serveur à un autre moment, et parce que j'ai un contrôle total sur l'ajout, le retrait et la modification des balises . – Flambino

Questions connexes