2010-12-30 5 views
7

Ich habe meine Sucher funktioniert wirklich gut, aber es neigt dazu, Ergebnisse zurückzugeben, die veraltet sind. Meine Seite ist ähnlich wie NerdDinner, wobei Ereignisse in der Vergangenheit irrelevant werden.Lucene.Net: Wie kann ich meinen Suchergebnissen einen Datumsfilter hinzufügen?

ich zur Zeit Indizierung wie diese
Anmerkung: mein Beispiel ist in VB.NET, aber ist mir egal, wenn Beispiele in 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 

Hinweis gegeben, wie ich ein " date "Index, der das Ereignisdatum speichert.

Meine Suche sieht dann aus wie dieser

''# 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 

ich folgendes habe versucht, aber es war vergeblich (eine Nullreferenceexception geworfen).

 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 

Ich fand auch die folgende Dokumentation, aber ich kann nicht Kopf oder Zahl davon machen
http://lucene.apache.org/java/1_4_3/api/org/apache/lucene/search/DateFilter.html

+0

Ok, ich dachte du hast mvc zurück hinzugefügt. Also dein ok mit einem IronPython oder IronRuby Beispiel? ;) – jfar

+0

:-p [uh das ist prolly push it] –

Antwort

9

Sie sind auf der aPI-Dokumentation von Lucene Verknüpfung 1.4.3 . Lucene.Net ist derzeit bei 2.9.2. Ich denke, ein Upgrade ist fällig.

Zuerst verwenden Sie Store.Yes viel. Gespeicherte Felder machen Ihren Index größer, was ein Leistungsproblem sein kann. Ihr Datum Problem kann leicht gelöst werden, indem Daten als Zeichenfolgen im Format "JJJJMMTTHHmmssfff" (das ist wirklich hohe Auflösung, bis zu Millisekunden) gespeichert werden. Möglicherweise möchten Sie die Auflösung verringern, um weniger Token zu erstellen, um die Indexgröße zu verringern.

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

Dann wenden Sie einen Filter auf Ihre Suche an (der zweite Parameter, an dem Sie gerade Nothing/null übergeben).

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

können Sie tun dies eine BooleanQuery mit Ihrer normalen Abfrage mit einem RangeQuery Kombination, sondern dass auch Affekt Scoring würde (die auf der Abfrage berechnet wird, nicht die Filter). Sie sollten auch vermeiden, die Abfrage zur Vereinfachung zu ändern, damit Sie wissen, welche Abfrage ausgeführt wird.

+0

das Beispiel war genau das, was ich bei einer Google-Suche gefunden habe. Ich benutze Lucene.Net v2.4.0.2 –

+0

Ich möchte, dass der Benutzer über 'date: dd/mm/yyyy 'suchen kann, wird das noch funktionieren? –

+0

Eine schnelle Suche in der magischen Changes.txt zeigt, dass 2.4.0 wurde am 2008-10-06 veröffentlicht und ist nach Zeile 1100 in einer langen Liste von Bugfixes und neuen Features. Ich denke, es gibt ein neues Indexformat (auf das Sie automatisch aktualisiert werden, aber ältere Versionen können nicht weiter lesen), aber dennoch sollten Sie ein Upgrade in Betracht ziehen. – sisve

7

Sie mehrere Abfragen mit einem BooleanQuery kombinieren. Da Lucene nur nach Text sucht, beachten Sie, dass das Datumsfeld in Ihrem Index nach dem höchstwertigen bis zum niederwertigsten Teil des Datums sortiert sein muss, dh im IS8601-Format ("2010-11-02T20: 49: 16.000000 + 00: 00")

Beispiel:

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

Alternativ, wenn ein Platzhalter ist nicht präzise genug, können Sie ein Add RangeQuery statt:

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 mist, wie muss ich herausfinden, wie man eine Boolesche Suche macht ;-) –