2009-10-12 15 views
5

Tengo un índice Lucene que contiene documentos que tienen un campo "tipo", este campo puede ser uno de tres valores "artículo", "foro" o " Blog". Deseo que el usuario pueda buscar dentro de estos tipos (hay una casilla de verificación para cada tipo de documento)Consulta de Lucene - "Emparejar exactamente uno de x, y, z"

¿Cómo creo una consulta Lucene dependiendo de qué tipos ha seleccionado el usuario?

Un par de requisitos previos son:

  • Si el usuario no selecciona uno de los tipos, quiero no resultados de ese tipo.
  • El orden de los resultados no debe verse afectado al restringir el campo de tipo.

Como referencia, si tuviera que escribir esto en SQL (para un "blog o foro de búsqueda") que escribiría:

SELECT * FROM Docs 
WHERE [type] in ('blog', 'forum') 

Respuesta

4

Como referencia, debe venir a través de cualquier otra persona este problema, aquí está mi solución:

IList<string> ALL_TYPES = new[] { "article", "blog", "forum" }; 
string q = ...; // The user's search string 
IList<string> includeTypes = ...; // List of types to include 
Query searchQuery = parser.Parse(q); 
Query parentQuery = new BooleanQuery(); 
parentQuery.Add(searchQuery, BooleanClause.Occur.SHOULD); 
// Invert the logic, exclude the other types 
foreach (var type in ALL_TYPES.Except(includeTypes)) 
{ 
    query.Add(
     new TermQuery(new Term("type", type)), 
     BooleanClause.Occur.MUST_NOT 
    ); 
} 
searchQuery = parentQuery; 

invertí la lógica (es decir, excluidos los tipos que el usuario no ha seleccionado), porque si no la haces el orden de los resultados se pierde. ¡No estoy seguro de por qué, aunque ...! Es una pena ya que hace que el código sea menos claro/mantenible, ¡pero al menos funciona!

3

añadir un limitaciones de rechazar documentos que no fueron seleccionadas. Por ejemplo, si se comprueba solamente "artículo", la restricción sería

-(type:forum type:blog) 
+0

Esto es lo que hice al final, aunque utilicé la API en lugar de crearla como una cadena, consulte mi respuesta si le interesa. – thatismatt

0

Aunque la sugerencia de Erickson parece estar bien, podría utilizar una restricción positiva AND con el término de búsqueda, tales como text:foo AND type:article para el caso único "artículo" fue verificado, o text:foo AND (type:article OR type:forum) para el caso, tanto "artículo" como "foro" fueron verificados.

+0

Curiosamente, las dos consultas "texto: foo AND (tipo: artículo O tipo: foro)" y "texto: foo AND -type: blog" no dan los mismos resultados, la primera consulta devuelve los blogs primero, mientras que el segundo la consulta mantiene el orden (es decir, los blogs y los artículos son mixtos). ¿Alguna idea de por qué? – thatismatt

+0

Lucene no tiene un operador "AND". Tiene operadores + (requerir) y - (prohibir). – erickson

+0

@erickson: Me permito diferir: p. http://incubator.apache.org/lucene.net/docs/2.1/Lucene.Net.QueryParsers.QueryParser.AND_OPERATOR.html –

Cuestiones relacionadas