2009-10-12 6 views
5

J'ai un index Lucene qui contient des documents qui ont un champ "type", ce champ peut être l'une des trois valeurs "article", "forum" ou " Blog". Je veux que l'utilisateur puisse rechercher dans ces types (il y a une case à cocher pour chaque type de document)Lucene requête - "Correspond exactement à un de x, y, z"

Comment créer une requête Lucene en fonction des types sélectionnés par l'utilisateur?

Quelques prérequis sont:

  • Si l'utilisateur ne sélectionne pas l'un des types, je veux pas résultats de ce type.
  • L'ordre des résultats ne devrait pas être affecté par la restriction du champ de type.

Pour référence si je devais écrire ceci dans SQL (pour un « blog ou recherche forum ») J'écris:

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

Répondre

4

Pour référence, si quelqu'un d'autre venir à travers ce problème, voici ma solution:

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; 

I inversé la logique (c.-à-types exclus l'utilisateur n'a pas choisi), parce que si vous ne faites pas la l'ordre des résultats est perdu. Je ne suis pas sûr de savoir pourquoi ...! C'est dommage car cela rend le code moins clair/maintenable, mais au moins ça marche!

3

Ajouter une contrainte de rejeter les documents qui ne sont pas sélectionnés. Par exemple, si seulement « article » a été cochée, la contrainte serait

-(type:forum type:blog) 
+0

C'est ce que j'ai fait à la fin, bien que j'aie utilisé l'API plutôt que de la créer comme une chaîne, voir ma réponse si vous êtes intéressé. – thatismatt

0

Alors que la suggestion de erickson semble bien, vous pouvez utiliser une contrainte positive ANDED avec votre terme de recherche, tels que text:foo AND type:article pour le seul cas « article » a été vérifié, ou text:foo AND (type:article OR type:forum) pour le cas à la fois "article" et "forum" ont été vérifiés.

+0

Curieusement les deux requêtes "texte: foo AND (type: article OU type: forum)" et "texte: foo AND -type: blog" ne donnent pas les mêmes résultats, la première requête retourne les blogs d'abord, où comme la seconde La requête maintient la commande (les blogs et les articles sont mélangés). Une idée pourquoi? – thatismatt

+0

Lucene n'a pas d'opérateur "AND". Il a + (exiger) et - (interdire) les opérateurs. – erickson

+0

@erickson: Je ne suis pas d'accord: par ex. http://incubator.apache.org/lucene.net/docs/2.1/Lucene.Net.QueryParsers.QueryParser.AND_OPERATOR.html –

Questions connexes