2012-09-28 15 views
6

Ho costruito un indice Lucene.net di libri. Tutto funziona bene, ma ho bisogno di aggiungere un altro modo per interrogare l'indice e non riesco a capire come farlo.Lucene.Net maggiore/minore di TermRangeQuery?

Fondamentalmente ogni libro ha una fascia d'età a cui è adatto. Questo è espresso da due colonne: minAge e maxAge. Entrambe le colonne sono numeri interi.

sto indicizzazione e la memorizzazione di questi campi nel seguente ciclo

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(); 
} 

Come potete vedere sto imbottitura i campi Minage e MaxAge come ho pensato che sarebbe stato più semplice per eseguire un TermRangeQuery contro di essa.

Tuttavia, ho bisogno di interrogare entrambe le colonne minAge e maxAge con un'età per vedere se l'età rientra nell'intervallo di età definito da minAge e maxAge.

Sql sarebbe

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

Purtroppo non riesco a vedere un modo per farlo. Questo è possibile anche in Lucene.Net?

risposta

10

Si dovrebbe essere in grado di farlo utilizzando le query di intervallo se la memoria serve. Questa è effettivamente l'inverso di una query gamma standard, ma si dovrebbe essere in grado di, qualcosa di simile:

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

Oppure, se il vostro costruire gli oggetti di query, un RangeQuery (o, meglio ancora, NumericRangeQuery) sia con la parte superiore o il limite inferiore null funziona come intervallo aperto.

Ho usato la sintassi sopra prima, ma il supporto sembra essere un po '... traballante. Se questo non funziona, si può sempre e solo impostare un adeguato basso limite inferiore (0) e ad alto limite superiore (ad esempio, 1000), come ad esempio:

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

che dovrebbe essere abbastanza sicuro, salvo eventuali Matusalemme.

+0

Marvelous usato il tuo consiglio e ha funzionato a meraviglia. Finito con la soluzione per la ricerca che illustrerò di seguito. – wingyip

4

Finito facendo questo con l'aiuto della risposta di femtoRgon sopra.

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

Problemi correlati