Comment utiliser Lucene.NET pour aider à mettre en œuvre la recherche sur un site comme Stack Overflow?
j'ai a posé une question similaire sur Meta Stack Overflow , mais qui traite spécifiquement de savoir si oui ou non Lucene.NET est utilisé sur le débordement de la pile.
le but de la question ici est plus d'une hypotétical, quant aux approches que l'on ferait si elles étaient d'utiliser Lucene.NET comme base pour la recherche dans le site et d'autres facteurs dans un site comme débordement de la cheminée [SO].
selon l'entrée sur le blog Stack Overflow intitulé " SQL 2008 Full-Text Search Problems "there was a strong indication que Lucene.NET était envisagé à un moment donné, mais il semble que ce n'est certainement pas le cas, comme le Commentaire par Geoff Dalgas le 19 février 2010:
Lucene.NET N'est pas utilisé pour Stack Overflow - nous utilisons SQL Server Indexation en texte intégral. La recherche est une zone où nous continuons à faire mineur pincer.
donc ma question est, comment utiliserait-on Lucene.NET dans un site qui a la même sémantique de débordement de pile?
voici un peu de contexte et ce que j'ai fait/pensé jusqu'à présent (oui, j'ai mis en œuvre la plupart de cela et la recherche est le dernier aspect que je dois remplir):
Technologies:
et bien sûr, la star du spectacle, Lucene.NET.
l'intention est également de passer à .NET/C# 4.0 dès que possible. Bien que je ne pense pas que c'est un changeur de jeu, il doit être noté.
avant d'entrer dans les aspects de Lucene.NET, il est important de souligner les aspects SQL Server 2008 de celui-ci, ainsi que les modèles impliqués.
Modèles
ce système a plus d'un type de modèle primaire par rapport au débordement de la cheminée. Quelques exemples de ces modèles sont:
- Questions: ce sont des questions que les gens peuvent poser. Les gens peuvent répondre aux questions, tout comme sur le débordement de la pile.
- Notes: il s'agit de projections à Sens Unique, donc contrairement à une question, vous faites une déclaration sur le contenu. Les gens ne peuvent pas poster de réponse à ça.
- événements: ce sont des données sur un événement en temps réel. Il contient des informations sur l'emplacement, la date et l'heure.
l'important à noter sur ces modèles:
- ils ont tous un Propriété Nom / Titre (texte) et propriété de corps (HTML) (les formats ne sont pas pertinents, car le contenu sera analysé de manière appropriée pour l'analyse).
- chaque instance d'un modèle a une URL unique sur le site
puis il y a les choses que la pile Overflow fournit qui IMO, sont décorateurs aux modèles. Ces décorateurs peuvent avoir différentes cardinalités, soit un-à-un ou un-à-plusieurs:
- Voix: à la clé sur l'utilisateur
- Réponses: en Option, comme un exemple, voir la Note ci-dessus,
- favoris: le modèle est-il listé comme favori d'un utilisateur?
- commentaires: (facultatif)
- Tag Associations: Les Tag sont dans une table séparée, afin de ne pas reproduire la tag pour chaque modèle. Il y a un lien entre le model et la table tag associations, et puis de la table tag associations à la table tags.
et il y a des comptes de soutien qui sont en eux-mêmes des décorateurs un à un pour les modèles qui sont attachés à eux de la même manière (généralement par un type d'id de modèle et l'id de modèle):
- décompte des voix: total des votes positifs, négatifs, Wilson Score interval (ceci est important, il va déterminer le niveau de confiance basé sur les votes pour une entrée, pour la plupart, supposer la limite inférieure de l'intervalle de Wilson).
Réponses (réponses) sont des modèles qui ont la plupart des décorateurs que la plupart des modèles, ils n'ont tout simplement pas d'un titre ou l'url, et si oui ou non un modèle a une réponse est facultative. Si les réponses sont autorisées, il s'agit bien sûr d'une relation de un à plusieurs.
SQL Server 2008
les tableaux suivent à peu près la présentation des modèles ci-dessus, avec des tableaux séparés pour les les décorateurs, ainsi que certaines tables et vues de soutien, procédures stockées, etc.
il est à noter que la décision de ne pas utiliser la recherche en texte intégral est basée principalement sur le fait qu'elle ne normalise pas les résultats comme Lucene.NET. Je suis ouvert aux suggestions sur la façon d'utiliser la recherche textuelle, mais je vais devoir effectuer des recherches à travers plusieurs types de modèles, alors gardez à l'esprit que je vais avoir besoin de normaliser le score d'une façon ou d'une autre .
Lucene.NET
C'est là le grand point d'interrogation. Voici ce que je pense de la fonctionnalité de débordement de pile ainsi que comment et ce que j'ai déjà fait.
indexation
Questions / Modèles
je crois que chaque modèle devrait avoir son propre index contenant un id unique pour le chercher rapidement basé sur un Terme instance de cette id (indexé, non analysé).
dans ce domaine, j'ai envisagé d'avoir Lucene.NET analyser chaque question/modèle et chaque réponse individuellement. Ainsi, s'il y avait une question et cinq réponses, la question et chacune des réponses seraient indexées comme une unité distincte.
l'idée ici est que la note de pertinence que Lucene.NET les rendements seraient plus faciles à comparer entre les modèles qui projettent de différentes façons (par exemple, quelque chose sans les réponses).
à titre d'exemple, une question pose le sujet, puis la réponse développe sur le sujet.
pour une note, qui n'a pas de réponse, il traite de la question de la présentation du sujet, puis de l'approfondir.
je crois que cela aidera à rendre les scores de pertinence plus pertinents les uns par rapport aux autres.
Tags
J'ai d'abord cru qu'ils doivent être conservés dans un index séparé avec plusieurs champs dont les id des documents dans les index de modèle. Ou, si c'est trop grand, il y a un index avec juste les tags et un autre index qui maintient la relation entre l'index des tags et les questions auxquelles ils sont appliqués. De cette façon, lorsque vous cliquez sur une balise (ou utilisez la structure URL), il est facile de voir d'une manière progressive que vous n'avez à "acheter dans" Si vous réussissez:
- si l'étiquette existe
- qui questionne les tags sont associés à
- les questions elles-mêmes
cependant, dans la pratique, faire une requête de tous les éléments basés sur des tags (comme cliquer sur une étiquette dans le débordement de la pile) est extrêmement facile avec SQL Server 2008. Basé sur le modèle ci-dessus, il nécessite simplement une requête telle que:
select
m.Name, m.Body
from
Models as m
left outer join TagAssociations as ta on
ta.ModelTypeId = <fixed model type id> and
ta.ModelId = m.Id
left outer join Tags as t on t.Id = ta.TagId
where
t.Name = <tag>
et puisque certaines propriétés sont partagées entre tous les modèles, il est assez facile de faire un UNION
entre les différents types de modèles/tableaux et de produire un ensemble cohérent de résultats.
ce serait similaire à un TermQuery
en Lucene.NET (je fais référence à la "documentation Java car il est complet, et Lucene.NET est destiné à être une traduction ligne par ligne de Lucene , donc tous les la documentation est la même).
la question qui vient avec l'utilisation Lucene.NET voici l'ordre de tri. Le score de pertinence pour un TermQuery quand il s'agit de tags n'est pas pertinent. C'est soit 1 ou 0 (Il l'A ou il ne l'a pas).
à ce point, le score de confiance (Intervalle de Wilson score) entre en jeu pour l'ordre des résultats.
cette partition peut être stockée dans Lucene.NET, mais pour trier les résultats sur ce field, il s'appuierait sur les valeurs stockées dans le cache de field, ce que je veux vraiment, vraiment éviter. Pour un grand nombre de documents, la cache de champ peut croître très grand (le score de Wilson est un double, et vous auriez besoin d'un double pour chaque document, qui peut être un grand tableau).
étant donné que je peux changer la déclaration SQL à l'ordre basé sur L'intervalle de score Wilson comme ceci:
select
m.Name, m.Body
from
Models as m
left outer join TagAssociations as ta on
ta.ModelTypeId = <fixed model type id> and
ta.ModelId = m.Id
left outer join Tags as t on t.Id = ta.TagId
left outer join VoteTallyStatistics as s on
s.ModelTypeId = ta.ModelTypeId and
s.ModelId = ta.ModelId
where
t.Name = <tag>
order by
--- Use Id to break ties.
s.WilsonIntervalLowerBound desc, m.Id
Il semble comme un choix facile à utilisez ceci pour gérer la fonctionnalité de débordement de pile "get all items tagged with ".
Réponses
à l'origine, je pensais que c'était dans un index séparé de ses propres, avec une clé de retour dans l'index des Questions.
je pense qu'il devrait y avoir une combinaison de chaque modèle et de chaque réponse (s'il y en a une) de sorte que les scores de pertinence entre les différents modèles soient plus" égaux " lorsqu'on les compare à chaque modèle. autre.
cela gonflerait bien sûr l'indice. Je suis un peu à l'aise avec ça maintenant.
Ou, est-il un moyen pour stocker dire, les modèles et les réponses que les documents de Lucene.NET et puis prendre les deux et être en mesure d'obtenir la note de pertinence pour une requête à traiter les deux documents comme un ? Si c'est le cas, ce serait idéal .
il y a bien sûr la question de quels champs seraient stockés, indexés, analysés (toutes les opérations peuvent être des opérations séparées, ou mélangées et appariées)? combien un indice?
Qu'en est-il de l'utilisation de stemmers/porters spéciaux pour les fautes d'orthographe (en utilisant la Métaphone) ainsi que des synonymes (il y a de la terminologie dans la communauté que je vais servir qui a son propre argot/terminologie pour certaines choses qui a des représentations multiples)?
coup de pouce
ceci est lié à l'indexation bien sûr, mais je pense qu'il mérite sa propre section.
Êtes-vous booster champs et/ou des documents? Si oui, comment pensez-vous stimuler? Est-ce que le boost est constant pour certains champs? Ou est-il recalculé pour les champs où vote/view/favorite/données externes est applicable.
Par exemple, dans le document, le titre obtenir un coup de pouce sur le corps? Si oui, quel boost facteurs, pensez-vous travailler? Qu'en est-tags?
la pensée ici est la même qu'elle est le long des lignes de débordement de la pile. Les termes dans le document de pertinence, mais si un document est identifié avec le terme, ou il est dans le titre, alors il devrait être renforcé.
Shashikant Kore suggère une structure de document comme ceci:
- titre
- Question
- Accepté de Répondre (Ou très voté réponse si il n'existe pas de réponse)
- toutes les réponses confondues
et ensuite en utilisant boost mais pas basé sur la valeur de vote brute. Je crois que J'ai couvert ça avec L'intervalle Wilson Score.
la question Est, doit-on appliquer l'impulsion à l'ensemble du document? Je pencherais pour un non sur celui-ci, parce que ça voudrait dire que je devrais réindexer le document à chaque fois qu'un l'utilisateur a voté sur le modèle.
recherche D'articles marqués
j'ai pensé à l'origine que lors de la recherche d'une balise (en cliquant spécifiquement sur une balise ou en utilisant la structure URL pour rechercher du contenu taggé), c'est un simple TermQuery contre l'index de balise pour la balise, puis dans l'index des associations (si nécessaire), puis retour aux questions, Lucene.NET il gère ça très vite.
toutefois, compte tenu de la notes ci-dessus concernant la facilité de faire cela dans SQL Server, j'ai opté pour cette route quand il s'agit de rechercher des éléments marqués.
Recherche Générale
alors maintenant, la question la plus en suspens est lorsqu'on fait une recherche générale d'une expression ou d'un terme par rapport au contenu, qu'est-ce et comment intégrez-vous d'autres renseignements (comme les votes) afin de déterminer les résultats dans l'ordre approprié? Par exemple, lorsque vous effectuez cette recherche sur ASP.NET MVC on Stack Overflow , ce sont les résultats des cinq premiers résultats (en utilisant l'onglet pertinence):
q votes answers accepted answer votes asp.net highlights mvc highlights
------- ------- --------------------- ------------------ --------------
21 26 51 2 2
58 23 70 2 5
29 24 40 3 4
37 15 25 1 2
59 23 47 2 2
noter que les points saillants sont seulement dans le titre et le résumé sur la page des résultats et ne sont que des indicateurs mineurs quant à ce que le terme vrai fréquence est dans le document, titre, étiquette, réponse (cependant ils sont appliqués, ce qui est une autre bonne question).
Comment tout cela?
à ce point, je sais que Lucene.NET j'obtiendrai un score de pertinence normalisé, et les données du vote me donneront un intervalle de score Wilson que je peux utiliser pour déterminer le score de confiance.
comment devrais-je envisager de combiner ces deux notes pour indiquer l'ordre de tri de l'ensemble des résultats en fonction de la pertinence et de la confiance?
Il est évident pour moi qu'il devrait être certains relation entre les deux, mais ce que cette relation devrait être m'échappe à ce stade. Je sais que je dois le peaufiner au fil du temps, mais je suis vraiment perdu sur cette partie.
mes premières réflexions sont que si le score de pertinence se situe entre 0 et 1 et le score de confiance se situe entre 0 et 1, Alors je pourrais faire quelque chose comme ceci:
1 / ((e ^ cs) * (e ^ rs))
de cette façon, on obtient une valeur normalisée qui approche 0 Plus le résultat est pertinent et sûr, et il peuvent être triés sur.
le problème principal avec cela est que si l'amplification est effectuée sur la balise et / ou le champ de titre, alors le score de pertinence est en dehors des limites de 0 à 1 (l'extrémité supérieure devient alors illimitée, et je ne sais pas comment traiter cela).
aussi, je crois que je vais devoir ajuster le score de confiance pour tenir compte des résultats de vote qui sont complètement négatifs. Depuis le compte de vote qui sont complètement résultat négatif dans un score Wilson intervalle avec une limite inférieure de 0, quelque chose avec -500 votes a le même score de confiance que quelque chose avec -1 vote, ou 0 votes.
heureusement, la limite supérieure passe de 1 à 0 à mesure que les résultats négatifs augmentent. Je pourrais changer le score de confiance pour être une gamme de -1 à 1, comme ceci:
confidence score = votetally < 0 ?
-(1 - wilson score interval upper bound) :
wilson score interval lower bound
le problème avec ceci est que le branchement 0 dans l'équation classera tous les éléments avec zéro vote en dessous de ceux avec un vote négatif décompte.
à cette fin, je pense que si le score de confiance va être utilisé dans une équation réciproque comme ci-dessus (je suis préoccupé par le débordement évidemment), alors il doit être retravaillé pour toujours être positif. Une façon d'y parvenir est:
confidence score = 0.5 +
(votetally < 0 ?
-(1 - wilson score interval upper bound) :
wilson score interval lower bound) / 2
mes autres préoccupations sont comment effectuer réellement le calcul donné Lucene.NET et SQL Server. J'hésite à mettre le score de confiance dans L'indice de Lucène parce qu'il nécessite l'utilisation de la cache de champ, qui peut avoir un impact énorme sur la consommation de mémoire (comme mentionné ci-dessus).
une idée que j'avais était d'obtenir la note de pertinence de Lucene.NET et puis en utilisant un paramètre de valeur de table pour streamer le score à SQL Server (avec les ids des éléments à sélectionner), à quel point je dois effectuer le calcul avec le score de confiance et ensuite retourner les données correctement ordonnées.
comme indiqué ci-dessus, il ya beaucoup d'autres questions que j'ai à ce sujet, et les réponses ont commencé à encadrer les choses, et continuera à développer les choses que la question et les réponses evovled.
5 réponses
les réponses que vous cherchez vraiment ne peut pas être trouvé en utilisant lucene seul. Vous avez besoin d'algorithmes de classement et de regroupement pour filtrer et comprendre les données et leur relation. Lucene peut vous aider à obtenir des données normalisées, mais vous avez besoin du bon algorithme après cela.
je vous recommande de vérifier un ou tous les livres suivants, ils vous aideront avec les mathématiques et vous faire pointer dans la bonne direction:
algorithmes de le Web Intelligent
l'indice de lucène aura les champs suivants:
- titre
- Question
- Accepté de Répondre (Ou très voté réponse si il n'existe pas de réponse)
- toutes les réponses confondues
Tous ces champs sont Analysés. La normalisation de la longueur est désactivée pour obtenir un meilleur contrôle sur le pointage.
l'ordre susmentionné des champs reflètent également leur importance par ordre décroissant. C'est-à-dire si la correspondance de requête dans le titre est plus importante que dans la réponse acceptée, tout le reste restant identique.
le # d'upvotes est pour la question et la réponse supérieure peut être capturé en stimulant ces champs. Cependant, le nombre brut de cotes élevées ne peut pas être utilisé comme valeurs de boost car il pourrait fausser les résultats de façon spectaculaire. (Une question avec 4 upvotes obtiendra le double du score d'un avec 2 upvotes.) Ces valeurs doivent être humidifié agressivement avant qu'ils puissent être utilisés comme facteur de boost. Utiliser quelque chose de logarithme naturel (pour upvotes >3) semble bon.
Le titrepeut être boosté d'une valeur légèrement supérieure à celle de la question.
bien que l'inter-enchaînement des questions n'est pas très commun, avoir un poids de pagerank comme base pour une question pourrait jeter vers le haut de quelques résultats intéressants.
Je ne considère pas les étiquettes de la question comme une information très utile pour la recherche. Les étiquettes sont agréables quand vous voulez juste parcourir les questions. La plupart du temps, les tags font partie du texte, donc rechercher les tags résultera correspondre à la question. Il est ouvert à la discussion.
une requête de recherche typique sera effectuée sur les quatre champs.
+(title:query question:query accepted_answer:query all_combined:query)
il s'agit d'un croquis général qui nécessitera des réglages importants pour obtenir les valeurs de boost à droite et les poids à droite pour les requêtes, s'il y a lieu. Experiementation montrera l' poids appropriés pour les deux dimensions de la qualité-pertinence et importance. Vous pouvez compliquer les choses en introduisant la récence comme paramètre aranking. L'idée ici est, si un problème se produit dans une version particulière du produit et est corrigé dans les révisions ultérieures, les nouvelles questions pourraient être plus utiles à l'utilisateur.
quelques rebondissements intéressants à rechercher pourraient être ajoutés. Une certaine forme de recherche synonymique de base pourrait être utile si seulement quelques résultats concordants sont trouvés. Pour exemple, "diminuer java taille de segment de mémoire" est le même que "la réduction du tas java taille."Mais, alors, cela signifie également "map reduce" va commencer à correspondre "map decrease."(Vérificateur d'orthographe est évident, mais je pense que les programmeurs sort de leurs requêtes correctement.)
vous avez probablement fait plus de réflexion sur ce sujet que la plupart des gens qui vont essayer de vous répondre (une partie de la raison pour laquelle il a été une journée et je suis votre première réponse, je suppose). Je vais juste essayer de répondre à vos trois dernières questions, B/c il y a juste beaucoup de choses que je n'ai pas le temps d'aborder, et je pense que ces trois questions sont les plus intéressantes (les questions de mise en œuvre physique vont probablement finir par être "prendre quelque chose, et puis le modifier au fur et à mesure que vous apprenez plus").
données de vote Je ne suis pas sûr que les votes rendent quelque chose de plus pertinent pour une recherche, franchement, les rend juste plus populaire. Si cela a du sens, j'essaie de dire que si un poste donné est pertinent à votre question Est la plupart du temps indépendante de savoir s'il était pertinent pour d'autres personnes. cela dit, il y a probablement au moins une faible corrélation entre les questions intéressantes et celles que les gens voudraient trouver. Les données du Vote sont probablement les plus utiles recherches fondées uniquement sur des données, par exemple les recherches de type "le plus populaire". Dans les recherches génériques basées sur le texte, Je ne donnerais probablement pas de poids pour les votes au début, mais j'envisagerais de travailler sur un algorithme qui fournit peut-être un léger poids pour le tri (donc, pas les résultats retournés, mais un petit coup de pouce à l'ordre d'entre eux).
réponses je serai d'accord w/ votre approche ici, sous réserve de certains tests; rappelez-vous que cela va être un processus itératif processus basé sur les commentaires des utilisateurs (vous aurez donc besoin de recueillir des paramètres pour savoir si les recherches ont donné des résultats positifs pour le chercheur)
autre N'oubliez pas le score de l'utilisateur aussi. Ainsi, les utilisateurs obtiennent des points sur SO aussi, et cela influence leur rang par défaut dans les réponses de chaque question à laquelle ils répondent (on dirait que c'est surtout pour briser sur les réponses qui ont le même nombre de bosses)
déterminer la pertinence est toujours délicat. Vous avez besoin de comprendre ce que vous essayez d'accomplir. Votre recherche en essayant de fournir une correspondance exacte pour un problème quelqu'un pourrait avoir ou est-il en essayant de fournir une liste des derniers articles sur un sujet?
une fois que vous avez compris ce que vous voulez retourner, Vous pouvez examiner l'effet relatif de chaque caractéristique que vous indexez. Qui va faire une bonne recherche. De là, vous modifiez en fonction des commentaires des utilisateurs (je suggère d'utiliser commentaires implicites au lieu de explicite sinon vous ennuierez l'utilisateur).
Comme à l'indexation, vous devriez essayer de mettre les données de sorte que chaque élément dispose de toutes les informations nécessaires pour le classer. Cela signifie que vous aurez besoin de saisir les données à partir d'un certain nombre d'endroits à construire. Certains systèmes d'indexation ont la capacité d'ajouter des valeurs aux éléments existants qui serait facile d'ajouter des scores à des questions lorsque les réponses sont arrivées. La simplicité ne ferait que vous reconstruire la question le plus souvent possible.
je pense que Lucène n'est pas bon pour ce travail. Vous avez besoin de quelque chose vraiment rapide avec une grande disponibilité... comme SQL Mais tu veux de l'open source?
je vous suggère D'utiliser Sphinx - http://www.sphinxsearch.com / C'est beaucoup mieux, et je parle avec l'expérience, j'ai utilisé les deux.
Sphinx est incroyable. L'est vraiment.