38 votes

Architecture de données optimale pour le balisage, les nuages et la recherche (comme StackOverflow)?

J'aimerais savoir comment Débordement de la Pile d'étiquetage et de recherche est conçu, car il semble fonctionner assez bien.

Ce qui est une bonne base de données/modèle de recherche si je veux faire tout ce qui suit:

  1. Le stockage des Étiquettes sur les différentes entités, (comment normaliser? c'est à dire de l'Entité, de l'Étiquette, et Entity_Tag tables?)
  2. La recherche d'articles, avec en particulier les tags
  3. La construction d'un nuage de tags de tous les mots qui s'appliquent à un particulier résultats de recherche
  4. Comment faire pour afficher une liste de balises pour chaque élément dans un résultat de recherche?

Peut-être qu'il fait sens pour stocker les balises dans une forme normalisée, mais aussi comme un espace délimité par des cordes pour l'application de l' #2, #4, et peut-être #3. Pensées?

J'ai entendu dire que le Débordement de Pile utilise Lucene pour la recherche. Est-ce vrai? J'ai entendu un couple de podcasts discuter SQL optimisation, mais rien sur Lucene. Si ils ne l'utilisation de Lucene, je me demandais comment beaucoup du résultat de la recherche vient de Lucene, et si le "drill-down" tag cloud vient de Lucene.

57voto

Winston Fassett Points 1810

Wow, je viens d'écrire un gros post et DONC étranglé et pendu sur elle, et quand j'appuie sur mon bouton de retour à la soumettre de nouveau, le balisage de l'éditeur était vide. aaargh.

Donc ici, je vais à nouveau...

Concernant un Débordement de Pile, il s'avère qu'ils utilisent SQL server 2005 de recherche de texte intégral.

Concernant le système d'exploitation des projets recommandés par @Subvention:

  • *DotNetKicks utilise la DB pour le marquage et Lucene pour la recherche de texte intégral. Il semble y avoir aucun moyen de combiner une recherche en texte intégral avec une recherche par tag
  • Kigg utilise Linq-to-SQL pour la recherche et la balise de requêtes. Les deux requêtes de jointure Histoires->StoryTags->Balises.
  • Les deux projets ont un 3-approche de table de marquage comme tout le monde semble généralement à recommander

J'ai aussi trouvé quelques autres questions sur de SORTE que j'avais raté avant:

Ce que je suis en train de faire, pour chacun des points que j'ai mentionnés:

  1. Dans la DB, 3 tables: Entité, Tag, Entity_Tag. J'utilise la DB pour:
    • Construire à l'échelle du site des nuages de tags
    • parcourir par balise (c'est à dire des urls comme SI s /questions/tagged/ASP.NET)
  2. Pour la recherche-je utiliser Lucene + NHibernate.Recherche
    • Les balises sont concat avais dans un TagString qui est indexé par Lucene
      • J'ai donc toute la puissance de la Lucene moteur de recherche (ET / OU / PAS de requêtes)
      • Je peux rechercher du texte et filtrer par tags dans le même temps
      • La Lucene analyseur fusionne les mots pour une meilleure étiquette de recherches (c'est à dire une balise de la recherche pour "test" sera également trouver des trucs marqués "test")
    • Lucene retourne un énorme potentiel de résultat, qui je paginer à 20 résultats
    • Ensuite, NHibernate, charge le résultat des Entités par Id, soit à partir de la bd ou de l'Entité cache
    • Il est donc tout à fait possible que les résultats de la recherche dans 0 hits de la DB
  3. Ne le faites pas encore, mais je pense que je vais probablement essayer de trouver un moyen de construire le nuage de tags à partir de la TagString dans Lucene, plutôt que de prendre une autre DB frappé
  4. Ne l'avez pas fait encore, mais je vais probablement stocker les TagString dans la DB de sorte que je puisse montrer à une Entité de la liste de balises sans avoir à en faire 2 de plus rejoint.

Cela signifie que chaque fois qu'une Entité balises sont modifiés, j'ai:

  • Insérer de nouvelles Balises qui n'existent pas déjà
  • Insérer/Supprimer de la table EntityTag
  • Mise À Jour De L'Entité.TagString
  • Mise à jour de l'index Lucene pour l'Entité

Étant donné que le rapport de lectures et d'écritures est très grand dans mon application, je pense que je suis ok avec ça. Le seul vraiment de temps est d'indexation Lucene, parce que Lucene ne peut insérer et de supprimer de son index, et donc je dois re-index de l'ensemble de l'entité afin de mettre à jour le TagString. Je ne suis pas enthousiasmé par cette idée, mais je pense que si je le fais dans un thread d'arrière-plan, il fera beau.

Le temps nous le dira...

5voto

Grant Points 190

Je ne sais pas si elles sont considérées comme optimales, mais les deux DotNetKicks et Kigg sont open source digg clone implémentations. Vous pouvez regarder comment ils font les tags et la recherche.

Mon meilleur devine sans beaucoup de délibération :)

  1. Je n'ai jamais aimé l'idée de la sérialisation des valeurs multiples dans un seul champ, donc délimité par des chaînes stockées dans un champ ne fait pas appel à moi... pourraient travailler pour la contiguïté des chemins avec des arbres, mais ceux-ci sont toujours commandés et les balises ne doivent pas être. Cela semble que ce serait d'impôt de l'opérateur LIKE pour le travail que vous pourriez faire pour les trouver.

Donc, mon attention est probablement Entité -> EntityTag < Tag.

  1. Cette approche permet de trouver des éléments par Tag assez facile, rejoindre en arrière à travers EntityTag, de l'appeler un jour.

  2. Vous avez besoin d'une opération secondaire ici pour sélectionner les différentes balises pour le jeu de résultats. Donc un.) tirez le résultat. b.) normaliser la balise de l'espace. Je pense que vous faites cela quelle que soit la réponse est la n ° 1 -- même la farce de balises dans un champ encore le rendement des balises en double (et que vous avez à désérialiser à effectuer cette op--donc plus de travail, un autre argument pour une approche relationnelle).

  3. Toujours facile. Voici un domaine où les sérialisé approche qui fonctionne le mieux. Pas besoin de les joindre pour enfant étiquettes, il est là, dans l'Entité. Cela dit, en tirant 0..n balises par l'intermédiaire de deux jointure de table ne semble pas trop difficile pour moi. Si vous parlez de la perf considérations, construire normalisé d'abord, puis d'optimiser via un cache ou denorm.

L'autre option est de "faire les deux". Cela se sent comme une optimisation prématurée, mais vous pouvez faire le plein approche normalisée à l'appui de n'importe quelle balise centrée sur les opérations et les sérialiser à persister à avoir un dénormalisée version là, dans l'Entité. Un peu plus de travail, un certain potentiel pour l'automne synchronisés si n'est pas entièrement couvert, mais le meilleur de deux mondes si il y a des limitations réelles entièrement normalisé dans votre cas d'utilisation.

Lucene est intéressant aussi, vous pouvez déclarer des métadonnées spécifiques dans les indices de l'IIRC, vous êtes donc susceptible de tirer parti de la balise de la recherche de cette façon. Mon soupçon est, si vous allez trop loin en bas de cette route, puis vous finissez par avoir un fossé entre ce que vous stockez dans la base de données et l'index à un certain point. Je peux parler favorablement sur Lucene, il est très performant et facile à utiliser, je crois .Texte utilisé pour ses capacités de recherche et il a appuyé toutes weblogs.asp.net avant de basculer à la Communauté du Serveur. Je garderais pour la recherche de texte intégral si MSSQL n'est pas dans l'image/suffisante, de résoudre la balise de questions dans la base de données de l'omi.

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