Tengo asked a simlar question on Meta Stack Overflow, pero eso se refiere específicamente a si Lucene.NET se usa o no en Stack Overflow.¿Cómo se usaría Lucene.NET para ayudar a implementar la búsqueda en un sitio como Stack Overflow?
El propósito de la pregunta aquí es más de un hipotética, en cuanto a lo que se acerca a uno haría que si fueran a utilizar Lucene.NET como base para la búsqueda en el sitio y otros factores en un sitio como Pila Desbordamiento [SO].
De acuerdo con la entrada en el blog de desbordamiento de pila titulado "SQL 2008 Full-Text Search Problems" hubo una fuerte indicación de que Lucene.NET estaba siendo considerado en algún momento, pero parece que definitivamente no es el caso, de acuerdo con el comentario por Geoff Dalgas el 19 de febrero de 2010:
Lucene.NET no está siendo utilizado para Stack Overflow - estamos utilizando SQL Server indexación de texto completo. La búsqueda es un área donde seguimos haciendo ajustes menores .
Así que mi pregunta es, ¿cómo se utilizan Lucene.NET en un sitio que tiene la misma semántica de Stack Overflow ?
Aquí es un poco de antecedentes y lo que he hecho/pensamiento acerca de lo que va (sí, he estado poniendo en práctica la mayor parte de esto y de búsqueda es el último aspecto que tengo que completar):
Tecnologías:
Y por supuesto, la estrella del espectáculo, Lucene.NET.
La intención también es pasar a .NET/C# 4.0 lo antes posible. Si bien no creo que sea un cambio de juego, debe tenerse en cuenta.
Antes de entrar en aspectos de Lucene.NET, es importante señalar los aspectos de SQL Server 2008, así como los modelos involucrados.
Modelos
Este sistema tiene más de un tipo de modelo primario en comparación con Stack Overflow . Algunos ejemplos de estos modelos son:
- Preguntas: Estas son preguntas que las personas pueden formular. Las personas pueden responder preguntas, al igual que en Stack Overflow.
- Notas: Estas son proyecciones unidireccionales, por lo que a diferencia de una pregunta, usted está haciendo una declaración sobre el contenido. La gente no puede publicar respuestas a esto.
- Eventos: se trata de datos sobre un evento en tiempo real. Tiene información de ubicación, información de fecha/hora.
Lo importante a tener en cuenta sobre estos modelos:
- Todos ellos tienen un Nombre/Título (texto) propiedad y un cuerpo (HTML) propiedad (los formatos son irrelevantes, ya que el contenido será analizado apropiadamente para el análisis).
- Cada instancia de un modelo tiene una URL única en el sitio
Luego están las cosas que se apilan desbordamiento proporciona cuales la OMI, son decoradores a los modelos. Estos decoradores pueden tener diferentes cardinalidades, ya sea ser uno-a-uno o uno-a-muchos:
- Votos: Afinado en el usuario
- Respuestas: Opcional, como un ejemplo, véase el caso notas anteriores
- Favorito: ¿El modelo aparece como favorito de un usuario?
- Comentarios: (opcional)
- Asociaciones de etiquetas: las etiquetas están en una tabla separada, para no duplicar la etiqueta de cada modelo. Hay un enlace entre el modelo y la tabla de asociaciones de etiquetas, y luego desde la tabla de asociaciones de etiquetas hasta la tabla de etiquetas.
Y hay recuentos de apoyo que en sí mismos son uno-a-uno decoradores a los modelos que tienen la forma adecuada para ellos de la misma manera (por lo general por un tipo de modelo de identificación y el modelo id):
- Conteo de votos: total positivo, votos negativos, Wilson Score interval (esto es importante, determinará el nivel de confianza basado en los votos para una entrada, en su mayor parte, suponga el límite inferior del intervalo Wilson).
Las respuestas (respuestas) son modelos que tienen la mayoría de los decoradores que la mayoría de los modelos tienen, simplemente no tienen un título o una url, y si un modelo tiene una respuesta es opcional. Si se permiten respuestas, es por supuesto una relación de uno a muchos.
SQL Server 2008
Las tablas más o menos siguen el diseño de los modelos anteriores, con mesas separadas para los decoradores, así como algunas mesas de apoyo y vistas, procedimientos almacenados, etc.
Cabe señalar que la decisión de no utilizar la búsqueda de texto completo se basa principalmente en el hecho de que no normaliza puntajes como Lucene.NET. Estoy abierto a sugerencias sobre cómo utilizar la búsqueda basada en texto, pero tendré que realizar búsquedas en varios tipos de modelos, así que tenga en cuenta que voy a necesitar normalizar el puntaje de alguna manera.
Lucene.NET
Aquí es donde el gran signo de interrogación es. Aquí están mis pensamientos hasta ahora sobre Stack Funcionalidad de desbordamiento, así como cómo y qué ya he hecho.
Indexación
Preguntas/Modelos
creo que cada modelo debe tener un índice de su propia que contiene un identificador único para buscar rápidamente hacia arriba sobre la base de una instancia plazo de ese id (indexados , no analizado).
En esta área, he considerado que Lucene.NET analice cada pregunta/modelo y cada respuesta individualmente. Entonces, si hubiera una pregunta y cinco respuestas, la pregunta y cada una de las respuestas se indexarían como una unidad por separado.
La idea aquí es que la puntuación de relevancia que devuelve Lucene.NET sería más fácil de comparar entre los modelos que se proyectan de diferentes maneras (por ejemplo, algo sin respuestas).
Como un ejemplo, una pregunta establece el tema, y luego la respuesta profundiza sobre el tema.
Para una nota, que no tiene respuestas, maneja la cuestión de presentar el tema y luego elaborarlo.
Creo que esto ayudará a que los puntajes de relevancia sean más relevantes el uno para el otro.
Etiquetas
Al principio, pensé que éstos deben mantenerse en un índice separado con múltiples campos que tienen los identificadores a los documentos del índice modelo apropiado. O, si es demasiado grande, hay un índice con solo las etiquetas y otro índice que mantiene la relación entre el índice de etiquetas y las preguntas a las que se aplican. De esta manera, cuando se hace clic en una etiqueta (o utiliza la estructura de la URL), es fácil ver de una manera progresiva que es suficiente con "comprar en" si tiene éxito:
- Si existe la etiqueta
- que cuestiona las etiquetas están asociados con
- las preguntas mismas
Sin embargo, en la práctica, haciendo una consulta de todos los elementos en función de las etiquetas (como hacer clic en una etiqueta en la pila desbordamiento) es extremadamente fácil con SQL Server 2008. Basado en el modelo anterior, se requiere simplemente una consulta como:
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>
Y puesto que ciertas propiedades se comparten entre todos los modelos, es bastante fácil de hacer un UNION
entre diferentes modelos Típicos/mesas y producir un conjunto coherente de resultados.
Esto sería análogo a un TermQuery
en Lucene.NET (estoy haciendo referencia a la Java documentation ya que es integral, y Lucene.NET pretende ser una traducción línea por línea del Lucene, por lo que toda la documentación es el mismo).
El problema que surge con el uso de Lucene.NET aquí es el del orden de clasificación. El puntaje de relevancia para un TermQuery cuando se trata de etiquetas es irrelevante. Es 1 o 0 (lo tiene o no).
En este punto, el puntaje de confianza (intervalo de puntuación de Wilson) entra en juego para ordenar los resultados.
Este puntaje podría almacenarse en Lucene.NET, pero para ordenar los resultados en este campo, se basaría en los valores almacenados en la memoria caché de campo, que es algo que realmente quiero evitar. Para una gran cantidad de documentos, el caché de campo puede crecer mucho (el puntaje de Wilson es el doble, y necesitaría uno doble para cada documento, que puede ser un conjunto grande).
Dado que puedo cambiar la instrucción SQL para el orden basado en el Wilson anotar intervalo de la siguiente manera:
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
Parece una elección fácil de usar esto para manejar la pieza de funcionalidad desbordamiento de pila "llegar todos los elementos etiquetados con <tag> ".
Respuestas
Originalmente, pensé que esto está en un índice separado de su propia, con una clave de nuevo en el índice de Preguntas.
Creo que debe haber una combinación de cada modelo y cada respuesta (si hay una) para que las puntuaciones de relevancia en los diferentes modelos sean más "iguales" cuando se comparen entre sí.
Esto, por supuesto, inflaría el índice. Estoy algo cómodo con eso ahora mismo.
O, ¿hay alguna forma de almacenar, digamos, los modelos y respuestas como documentos individuales en Lucene.NET y luego tomar ambos y poder obtener el puntaje de relevancia para una consulta tratando ambos documentos como uno? Si es así, esto sería ideal.
Por supuesto, existe la pregunta de qué campos se almacenarán, indizarán, analizarán (¿todas las operaciones pueden ser operaciones separadas o mix-and-matching)? ¿Cuánto indexaría uno?
¿Qué pasa con el uso de stemmers/porters especiales para errores de ortografía (usando Metaphone) y sinónimos (hay terminología en la comunidad que daré servicio que tiene su propia jerga/terminología para ciertas cosas que tiene múltiples representaciones)?
Boost
Esto se relaciona con la indexación por supuesto, pero creo que merece su propia sección.
¿Está aumentando los campos y/o documentos? Si es así, ¿cómo los impulsas? ¿El impulso es constante para ciertos campos? O se vuelve a calcular para campos en los que se aplica el voto/vista/datos favoritos/externos.
Por ejemplo, en el documento, ¿el título recibe un impulso sobre el cuerpo? Si es así, ¿qué factores de impulso crees que funcionan bien? ¿Qué pasa con las etiquetas?
La idea aquí es la misma que en la línea de Stack Overflow. Los términos en el documento tienen relevancia, pero si un documento está etiquetado con el término, o está en el título, entonces debe ser potenciado.
Shashikant Kore sugiere una estructura de documento como este:
- Título
- Pregunta
- respuesta aceptada (O respuesta altamente votado si no hay respuesta aceptada)
- Todas las respuestas combinado
Y luego usar el impulso pero no basado en el valor de voto sin procesar. Creo que tengo eso cubierto con el intervalo de puntuación de Wilson.
La pregunta es, ¿debería aplicarse el impulso a todo el documento? Me inclino por no en este caso, porque significaría que tendría que reindexar el documento cada vez que un usuario votara en el modelo.
Búsqueda de artículos etiquetados
principio pensé que al consultar una etiqueta (haciendo clic en concreto en uno o usando la estructura de URL para buscar contenido etiquetado), que es una TermQuery simple contra el índice de etiqueta para la etiqueta, luego en el índice de asociaciones (si es necesario) y luego de vuelta a las preguntas, Lucene.NET maneja esto muy rápidamente.
Sin embargo, teniendo en cuenta las notas anteriores sobre lo fácil que es hacer esto en SQL Server, he optado por esa ruta cuando se trata de buscar elementos etiquetados.
General Búsqueda
Así que ahora, la pregunta más sobresaliente es cuando se hace una frase general o término de búsqueda contra los contenidos, qué y cómo se puede integrar otra información (como votos) con el fin de determinar los resultados en el orden correcto? Por ejemplo, al realizar esta búsqueda en ASP.NET MVC on Stack Overflow, estos son los recuentos de los cinco mejores resultados (cuando se utiliza la pestaña relevancia):
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
Tenga en cuenta que los aspectos más destacados son sólo en el título y el resumen en la página de resultados y son solo indicadores menores en cuanto a cuál es la frecuencia del término verdadero en el documento, título, etiqueta, respuesta (sin importar cómo se apliquen, que es otra buena pregunta).
¿Cómo se combina todo esto?
En este punto, sé que Lucene.NET devolverá un puntaje de relevancia normalizado, y los datos de voto me darán un intervalo de puntuación de Wilson que puedo usar para determinar el puntaje de confianza.
¿Cómo debo considerar la combinación de dos puntajes para indicar el orden de clasificación del conjunto de resultados según la relevancia y la confianza?
Es obvio para mí que debería haber alguna relación entre los dos, pero esa relación debería ser evadida en este momento. Sé que tengo que refinarlo a medida que pasa el tiempo, pero realmente estoy perdido en esta parte.
Mis pensamientos iniciales son si la puntuación de relevancia es beween 0 y 1 y la puntuación de confianza está entre 0 y 1, entonces yo podría hacer algo como esto:
1/((e^cs) * (e^rs))
De esta manera, se obtiene un valor normalizado que se acerca a 0, el resultado es más relevante y seguro, y se puede ordenar sobre eso.
El problema principal es que si el refuerzo se realiza en la etiqueta o en el campo de título, entonces la puntuación de relevancia está fuera de los límites de 0 a 1 (el extremo superior se vuelve ilimitado y no sé cómo lidiar con eso).
Además, creo que tendré que ajustar el puntaje de confianza para dar cuenta de los votos que son completamente negativos. Dado que los conteos de votos que son completamente negativos dan como resultado un intervalo de puntuación de Wilson con un límite inferior de 0, algo con -500 votos tiene el mismo puntaje de confianza que algo con -1 voto, o 0 votos.
Afortunadamente, el límite superior disminuye de 1 a 0 a medida que aumentan los votos negativos. Podría cambiar la puntuación de confianza que haya un rango de -1 a 1, así:
confidence score = votetally < 0 ?
-(1 - wilson score interval upper bound) :
wilson score interval lower bound
El problema con esto es que enchufar 0 en la ecuación alineará todos los elementos con cero votos por debajo de los que tienen votos negativos.
Para ese fin, estoy pensando que si el puntaje de confianza va a ser usado en una ecuación recíproca como la anterior (me preocupa el desbordamiento obviamente), entonces debe ser modificado para que siempre sea positivo. Una forma de lograr esto es:
confidence score = 0.5 +
(votetally < 0 ?
-(1 - wilson score interval upper bound) :
wilson score interval lower bound)/2
Mis otras preocupaciones son cómo realizar el cálculo realidad dada Lucene.NET y SQL Server. Dudo en poner el puntaje de confianza en el índice de Lucene porque requiere el uso del caché de campo, lo que puede tener un gran impacto en el consumo de memoria (como se mencionó anteriormente).
Una idea que tuve fue obtener el puntaje de relevancia de Lucene.NET y luego usar un table-valued parameter para transmitir el puntaje a SQL Server (junto con los identificadores de los elementos a seleccionar), en ese punto realizaría el cálculo con el puntaje de confianza y luego devolver los datos debidamente ordenados.
Como dije antes, hay muchas otras preguntas que tengo sobre esto, y las respuestas han comenzado a enmarcar las cosas, y seguirán ampliándose a medida que la pregunta y las respuestas mejoren.
@Paul: He actualizado la pregunta para reflejar cómo los datos de votación (que es un puntaje de confianza) se relacionan con la puntuación de relevancia, así como pensamientos sobre respuestas No creo que vaya a utilizar la reputación del usuario para evaluar los resultados de clasificación de búsqueda, pero en términos de respuestas de desempate en términos de votos, es bastante fácil hacerlo en SQL Server. – casperOne