Lucene.Net: как добавить фильтр дат в Результаты поиска?
у меня есть мой искатель работает очень хорошо, однако он имеет тенденцию возвращать результаты, которые устарели. Мой сайт очень похож на NerdDinner, где события в прошлом становятся неактуальными.
В настоящее время я индексирую вот так
Примечание: мой пример в VB.NET, но мне все равно, если примеры приведены в 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
обратите внимание, как у меня есть индекс "дата", который хранит дату события.
Мой поиск тогда выглядит так это
''# 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
я попробовал следующее, Но это было бесполезно (бросил исключение 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
Я также нашел следующую документацию, но я не могу сделать головы или хвосты it
http://lucene.apache.org/java/1_4_3/api/org/apache/lucene/search/DateFilter.html
2 ответов
вы ссылаетесь на документацию api Lucene 1.4.3. Lucene.Net в настоящее время 2.9.2. Я думаю, что обновление должно быть.
во-первых, вы используете магазина.Да много. Сохраненные поля сделают ваш индекс больше, что может быть проблемой производительности. Ваша проблема с датой может быть легко решена путем хранения дат в виде строк в формате "yyyyMMddHHmmssfff" (это действительно высокое разрешение, вплоть до миллисекунд). Вы можете уменьшить разрешение, чтобы создать меньше токенов для уменьшения индекса размер.
var dateValue = DateTools.DateToString(searchableEvent.EventDate, DateTools.Resolution.MILLISECOND);
doc.Add(new Field("date", dateValue, Field.Store.YES, Field.Index.NOT_ANALYZED));
затем вы применяете фильтр к вашему поиску (второй параметр, где вы в настоящее время проходите в Nothing/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);
Вы можете сделать это, используя BooleanQuery, объединяющий ваш обычный запрос с RangeQuery, но это также повлияет на оценку (которая рассчитывается по запросу, а не фильтру). Вы также можете избежать изменения запроса для простоты, поэтому вы знаете, какой запрос выполняется.
вы можете объединить несколько запросов с BooleanQuery
. Поскольку Lucene ищет только текст, обратите внимание, что поле даты в вашем индексе должно быть упорядочено по наиболее значимой и наименее значимой части даты, т. е. в формате IS8601 ("2010-11-02T20:49:16.000000+00:00")
пример:
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);
альтернативно, если подстановочный знак недостаточно точен, вы можете добавить 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);