2012-09-28 26 views
6

He creado un índice de libros Lucene.net. Todo está funcionando bien, pero necesito agregar otra forma de consultar el índice y no puedo encontrar la manera de hacerlo.Lucene.Net mayor que/menor que TermRangeQuery?

Básicamente, cada libro tiene un rango de edad para el que es adecuado. Esto se expresa mediante dos columnas, a saber, minAge y maxAge. Ambas columnas son números enteros.

estoy indexación y almacenamiento de estos campos en el siguiente bucle

foreach (var catalogueBook in books) 
{ 
    var book = new Book(catalogueBook.CatalogueBookNo,catalogueBook.IssueId); 

    var strTitle = book.FullTitle ?? ""; 
    var strAuthor = book.Author ?? ""; 
    // create a Lucene document for this book 
    var doc = new Document(); 

    // add the ID as stored but not indexed field, not used to query on 
    doc.Add(
     new Field(
      "BookId", 
      book.CatalogueBookNo.ToString(System.Globalization.CultureInfo.InvariantCulture), 
      Field.Store.YES, 
      Field.Index.NOT_ANALYZED_NO_NORMS, 
      Field.TermVector.NO)); 

    // add the title and author as stored and tokenized fields, the analyzer processes the content 
    doc.Add(
     new Field("FullTitle", 
      strTitle.Trim().ToLower(), 
      Field.Store.YES, 
      Field.Index.ANALYZED, 
      Field.TermVector.NO)); 

    doc.Add(
     new Field("Author", 
      strAuthor.Trim().ToLower(), 
      Field.Store.YES, 
      Field.Index.ANALYZED, 
      Field.TermVector.NO)); 

    doc.Add(
     new Field("IssueId", 
      book.IssueId, 
      Field.Store.YES, 
      Field.Index.NOT_ANALYZED_NO_NORMS, 
      Field.TermVector.NO)); 

    doc.Add(
     new Field(
      "PublicationId", 
      book.PublicationId.Trim().ToLower(), 
      Field.Store.YES, 
      Field.Index.NOT_ANALYZED_NO_NORMS, 
      Field.TermVector.NO)); 

    doc.Add(
     new Field(
      "MinAge", 
      book.MinAge.ToString("0000"), 
      Field.Store.YES, 
      Field.Index.NOT_ANALYZED_NO_NORMS, 
      Field.TermVector.NO)); 

    doc.Add(
     new Field(
      "MaxAge", 
      book.MaxAge.ToString("0000"), 
      Field.Store.YES, 
      Field.Index.NOT_ANALYZED_NO_NORMS, 
      Field.TermVector.NO)); 

    doc.Add(new NumericField("Price",Field.Store.YES,true).SetDoubleValue(Convert.ToDouble(book.Price))); 

    //Now we can loop through categories 
    foreach(var bc in book.GetBookCategories()) 
    { 
     doc.Add(
      new Field("CategoryId", 
       bc.CategoryId.Trim().ToLower(), 
       Field.Store.YES, 
       Field.Index.NOT_ANALYZED_NO_NORMS, 
       Field.TermVector.NO)); 
    } 

    // add the document to the index 
    indexWriter.AddDocument(doc); 
} 

// make lucene fast 
indexWriter.Optimize(); 
} 

Como se puede ver que estoy carnes de los campos minage y MaxAge como pensé que sería más fácil de ejecutar un TermRangeQuery contra ella.

Sin embargo, necesito consultar las columnas minAge y maxAge con una edad para ver si esa edad coincide con el rango de edad definido por minAge y maxAge.

SQL sería

Select * 
From books 
where @age >= minAge and @age <= maxAge 

Por desgracia, no puede ver una manera de hacer esto. ¿Es esto posible en Lucene.Net?

Respuesta

10

Debería poder hacer esto utilizando las consultas de rango si la memoria sirve. Esto es efectivamente la inversa de una consulta estándar gama, pero debe ser capaz de, algo así como:

+minAge:[* TO @age] +maxAge:[@age TO *] 

O, si su construcción de los objetos de consulta, una RangeQuery (o mejor aún, NumericRangeQuery), ya sea con la parte superior o un límite inferior nulo funciona como un rango abierto.

He utilizado la sintaxis anterior, pero el soporte parece ser un poco ... inestable. Si eso no funciona, siempre puede establecer una adecuada baja cota inferior (0) y alta cota superior (por ejemplo, 1000), tales como:

+minAge:[0000 TO @age] +maxAge:[@age TO 1000] 

Cuáles deberían ser lo suficientemente seguro, salvo alguna matusalenes.

+0

maravilloso utiliza su consejo y funcionó un placer. Terminé con la solución para la búsqueda que resumiré a continuación. – wingyip

4

Terminamos haciendo esto con la ayuda de la respuesta de femtoRgon anterior.

var q = new TermRangeQuery("MinAge", "0000",searchTerms.Age.ToString("0000"), true, true); 
mainQuery.Add(q, BooleanClause.Occur.MUST); 
q = new TermRangeQuery("MaxAge", searchTerms.Age.ToString("0000"),"9999", true, true); 
mainQuery.Add(q, BooleanClause.Occur.MUST); 

Ala