2009-10-12 18 views
5

Ho un indice Lucene che contiene documenti che hanno un campo "tipo", questo campo può essere uno dei tre valori "articolo", "forum" o " blog". Voglio che l'utente sia in grado di cercare all'interno di questi tipi (non v'è una casella di controllo per ogni tipo di documento)Query Lucene - "Corrispondenza esatta di x, y, z"

Come si crea una query Lucene dipende da quale tipo l'utente ha selezionato?

Un paio di prerequisiti sono:

  • Se l'utente non seleziona uno dei tipi, voglio non risultati di quel tipo.
  • L'ordine dei risultati non deve essere influenzato limitando il campo del tipo.

Per avere un riferimento, se dovessi scrivere questo in SQL (per un "blog o forum di ricerca") mi piacerebbe scrivere:

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

risposta

4

Per riferimento, chiunque altro dovrebbe incontrare questo problema, ecco la mia soluzione:

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; 

ho invertito la logica (cioè esclusi i tipi l'utente non aveva scelto), perché se non lo fai l'ordine dei risultati è perso. Non sono sicuro del perché comunque ...! È un peccato perché rende il codice meno chiaro/manutenibile, ma almeno funziona!

3

Aggiungi un vincoli di rifiutare i documenti che non sono stati selezionati. Ad esempio, se solo "articolo" è stata selezionata, il vincolo sarebbe

-(type:forum type:blog) 
+0

Questo è quello che ho fatto alla fine, anche se ho usato l'API invece di crearlo come una stringa, vedere la mia risposta se sei interessato. – thatismatt

0

Mentre il suggerimento di Erickson sembra in ordine, è possibile utilizzare un vincolo positivo AND con il termine di ricerca, come ad esempio text:foo AND type:article per il caso unico "articolo" è stato controllato, o text:foo AND (type:article OR type:forum) per il caso sia "articolo" che "forum" sono stati controllati.

+0

Intrigantemente le due query "text: foo AND (type: article OR type: forum)" e "text: foo AND -type: blog" non danno gli stessi risultati, la prima query restituisce prima i blog, dove come seconda la query mantiene l'ordine (cioè i blog e gli articoli sono misti). Qualche idea del perché? – thatismatt

+0

Lucene non ha un operatore "AND". Ha + (richiede) e - (proibisce) operatori. – erickson

+0

@erickson: mi permetto di dissentire: ad es. http://incubator.apache.org/lucene.net/docs/2.1/Lucene.Net.QueryParsers.QueryParser.AND_OPERATOR.html –

Problemi correlati