2010-12-30 14 views
7

Mój program wyszukujący działa naprawdę dobrze, jednak ma tendencję do zwracania wyników, które są przestarzałe. Moja strona jest podobna do NerdDinner, dzięki czemu wydarzenia z przeszłości stają się nieistotne.Lucene.Net: Jak mogę dodać filtr daty do moich wyników wyszukiwania?

Jestem obecnie indeksowania jak ten
uwaga: mój przykład jest w VB.NET, ale nie obchodzi mnie, jeśli podano przykłady w 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 

zauważyć, jak mam " data "indeks przechowujący datę wydarzenia.

Moje poszukiwania wtedy wygląda to

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

Próbowałem następujących, ale to było na próżno (rzucił 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 

Znalazłem również następujące dokumenty, ale nie mogę dokonać monetą z nim
http://lucene.apache.org/java/1_4_3/api/org/apache/lucene/search/DateFilter.html

+0

Ok, myślałem, że dodałeś mvc z powrotem. Więc twoje ok z przykładem IronPython lub IronRuby? ;) – jfar

+0

:-p [uh to pchanie go] –

Odpowiedz

9

łączysz do dokumentacji aPI Lucene 1.4.3 . Lucene.Net jest obecnie w 2.9.2. Myślę, że należy dokonać aktualizacji.

Po pierwsze, używasz Store.Tak wiele. Przechowywane pola zwiększą twój indeks, co może być problemem z wydajnością. Problem z datą można łatwo rozwiązać, zapisując daty jako łańcuchy w formacie "yyyyMMddHHmmssfff" (to naprawdę wysoka rozdzielczość, do milisekund). Możesz zmniejszyć rozdzielczość, aby utworzyć mniej tokenów, aby zmniejszyć rozmiar indeksu.

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

Następnie należy zastosować filtr wyszukiwania (drugi parametr, gdzie aktualnie przechodzą w nic/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); 

Można to zrobić za pomocą BooleanQuery łącząc swoje normalne zapytanie o RangeQuery, ale które mają również wpływ na zabicie (który jest obliczany na zapytania, a nie filtr). Możesz również uniknąć modyfikowania zapytania w celu uproszczenia, dzięki czemu wiesz, jakie zapytanie jest wykonywane.

+0

przykład był tym, co znalazłem robi wyszukiwania Google. Używam Lucene.Net v2.4.0.2 –

+0

Czy chcę, aby użytkownik mógł wyszukiwać przez 'date: dd/mm/yyyy' czy to nadal będzie działać? –

+0

Szybkie wyszukiwanie w magicznym pliku Changes.txt pokazuje, że 2.4.0 zostało wydane 2008-10-06 i jest po linii 1100 w długiej liście poprawek i nowych funkcji. Domyślam się, że istnieje nowy format indeksu (do którego będziesz automatycznie uaktualniany, ale starsze wersje nie mogą dalej czytać), ale mimo to powinieneś rozważyć ulepszenie. – sisve

7

Można łączyć wiele zapytań z BooleanQuery. Ponieważ Lucene przeszukuje tylko tekst, że pole daty w twoim indeksie musi być uporządkowane przez najbardziej znaczącą dla najmniej znaczącej części daty, tj. W formacie IS8601 ("2010-11-02T20: 49: 16.000000 + 00: 00")

Przykład:

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

Ewentualnie jeśli wieloznaczny nie jest wystarczająco precyzyjny można dodać RangeQuery zamiast:

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

o cholera, jak muszę wymyślić, jak zrobić boolean wyszukiwania ;-) –

Powiązane problemy