2010-12-30 5 views
7

Tengo mi buscador funcionando muy bien, sin embargo, tiende a devolver los resultados que están obsoletos. Mi sitio es muy parecido a NerdDinner por el cual los eventos en el pasado se vuelven irrelevantes.Lucene.Net: ¿Cómo puedo agregar un filtro de fecha a mis resultados de búsqueda?

estoy actualmente indexación como esto
nota: mi ejemplo es en VB.NET, pero no me importa si se dan ejemplos en C#

Public Function AddIndex(ByVal searchableEvent As [Event]) As Boolean Implements ILuceneService.AddIndex 

     Dim writer As New IndexWriter(luceneDirectory, New StandardAnalyzer(), False) 

     Dim doc As Document = New Document 

     doc.Add(New Field("id", searchableEvent.ID, Field.Store.YES, Field.Index.UN_TOKENIZED)) 
     doc.Add(New Field("fullText", FullTextBuilder(searchableEvent), Field.Store.YES, Field.Index.TOKENIZED)) 
     doc.Add(New Field("user", If(searchableEvent.User.UserName = Nothing, 
            "User" & searchableEvent.User.ID, 
            searchableEvent.User.UserName), 
           Field.Store.YES, 
           Field.Index.TOKENIZED)) 
     doc.Add(New Field("title", searchableEvent.Title, Field.Store.YES, Field.Index.TOKENIZED)) 
     doc.Add(New Field("location", searchableEvent.Location.Name, Field.Store.YES, Field.Index.TOKENIZED)) 
     doc.Add(New Field("date", searchableEvent.EventDate, Field.Store.YES, Field.Index.UN_TOKENIZED)) 

     writer.AddDocument(doc) 

     writer.Optimize() 
     writer.Close() 
     Return True 

    End Function 

Observe cómo tengo un " fecha "índice que almacena la fecha del evento.

Mi búsqueda a continuación, se parece a esto

''# code omitted 
     Dim reader As IndexReader = IndexReader.Open(luceneDirectory) 
     Dim searcher As IndexSearcher = New IndexSearcher(reader) 
     Dim parser As QueryParser = New QueryParser("fullText", New StandardAnalyzer()) 
     Dim query As Query = parser.Parse(q.ToLower) 

     ''# We're using 10,000 as the maximum number of results to return 
     ''# because I have a feeling that we'll never reach that full amount 
     ''# anyways. And if we do, who in their right mind is going to page 
     ''# through all of the results? 
     Dim topDocs As TopDocs = searcher.Search(query, Nothing, 10000) 
     Dim doc As Document = Nothing 

     ''# loop through the topDocs and grab the appropriate 10 results based 
     ''# on the submitted page number 
     While i <= last AndAlso i < topDocs.totalHits 
       doc = searcher.Doc(topDocs.scoreDocs(i).doc) 
       IDList.Add(doc.[Get]("id")) 
       i += 1 
     End While 
''# code omitted 

Yo probé la siguiente, pero fue en vano (tiró un NullReferenceException).

 While i <= last AndAlso i < topDocs.totalHits 
      If Date.Parse(doc.[Get]("date")) >= Date.Today Then 
       doc = searcher.Doc(topDocs.scoreDocs(i).doc) 
       IDList.Add(doc.[Get]("id")) 
       i += 1 
      End If 
     End While 

También encontré la siguiente documentación, pero no puedo hacer cara o cruz de la misma
http://lucene.apache.org/java/1_4_3/api/org/apache/lucene/search/DateFilter.html

+0

Ok, pensé que había agregado mvc. ¿Estás de acuerdo con un ejemplo de IronPython o IronRuby? ;) – jfar

+0

:-p [eso es prolly empujarlo] –

Respuesta

9

va a asociar a la documentación de la API de Lucene 1.4.3 . Lucene.Net se encuentra actualmente en 2.9.2. Creo que se debe una actualización.

En primer lugar, está utilizando Store.Yes mucho. Los campos almacenados aumentarán su índice, lo que puede ser un problema de rendimiento. Su problema de fecha puede resolverse fácilmente almacenando las fechas como cadenas en el formato "aaaamMMddHHmmssfff" (que es realmente de alta resolución, hasta milisegundos). Es posible que desee reducir la resolución para crear menos tokens para reducir el tamaño de su índice.

var dateValue = DateTools.DateToString(searchableEvent.EventDate, DateTools.Resolution.MILLISECOND); 
doc.Add(new Field("date", dateValue, Field.Store.YES, Field.Index.NOT_ANALYZED)); 

A continuación, se aplica un filtro a su búsqueda (el segundo parámetro, donde se pasa actualmente en Nada/null).

var dateValue = DateTools.DateToString(DateTime.Now, DateTools.Resolution.MILLISECOND); 
var filter = FieldCacheRangeFilter.NewStringRange("date", 
       lowerVal: dateValue, includeLower: true, 
       upperVal: null, includeUpper: false); 
var topDocs = searcher.Search(query, filter, 10000); 

Usted puede hacer esto utilizando una combinación de BooleanQuery su consulta normal con un RangeQuery, sino que también afectaría puntuación (que se calcula sobre la consulta, no el filtro). También es posible que desee evitar modificar la consulta por simplicidad, para que sepa qué consulta se ejecuta.

+0

el ejemplo fue justo lo que encontré haciendo una búsqueda en Google. Estoy usando Lucene.Net v2.4.0.2 –

+0

Quiero que el usuario pueda buscar a través de 'date: dd/mm/aaaa' ¿seguirá funcionando? –

+0

Una búsqueda rápida en el Magic Changes.txt muestra que 2.4.0 fue lanzado el 2008-10-06, y está después de la línea 1100 en una larga lista de correcciones de errores y nuevas características. Supongo que hay un nuevo formato de índice (al que se actualizará automáticamente, pero las versiones anteriores no pueden seguir leyendo), pero aún así, debería considerar una actualización. – sisve

7

Se pueden combinar varias consultas con un BooleanQuery. Como Lucene solo busca texto, tenga en cuenta que el campo de fecha de su índice debe ordenarse de la parte más significativa a la menos significativa de la fecha, es decir, en formato IS8601 ("2010-11-02T20: 49: 16.000000 + 00: 00")

Ejemplo:

Lucene.Net.Index.Term searchTerm = new Lucene.Net.Index.Term("fullText", searchTerms); 
Lucene.Net.Index.Term dateRange = new Lucene.Net.Index.Term("date", "2010*"); 

Lucene.Net.Search.Query termQuery = new Lucene.Net.Search.TermQuery(searchTerm); 
Lucene.Net.Search.Query dateRangeQuery = new Lucene.Net.Search.WildcardQuery(dateRange); 

Lucene.Net.Search.BooleanQuery query = new Lucene.Net.Search.BooleanQuery(); 
query.Add(termQuery, BooleanClause.Occur.MUST); 
query.Add(dateRangeQuery, BooleanClause.Occur.MUST); 

Alternativamente, si un comodín no es lo suficientemente precisa puede agregar una vez RangeQuery:

Lucene.Net.Search.Query termQuery = new Lucene.Net.Search.TermQuery(searchTerm); 
Lucene.Net.Index.Term date1 = new Lucene.Net.Index.Term("date", "2010-11-02*"); 
Lucene.Net.Index.Term date2 = new Lucene.Net.Index.Term("date", "2010-11-03*"); 
Lucene.Net.Search.Query dateRangeQuery = new Lucene.Net.Search.RangeQuery(date1, date2, true); 

Lucene.Net.Search.BooleanQuery query = new Lucene.Net.Search.BooleanQuery(); 
query.Add(termQuery, BooleanClause.Occur.MUST); 
query.Add(dateRangeQuery, BooleanClause.Occur.MUST); 
+0

oh mierda, cómo tengo que averiguar cómo hacer una búsqueda booleana ;-) –

Cuestiones relacionadas