Lucene.Net: Как я могу добавить фильтр даты в мои результаты поиска? - PullRequest
7 голосов
/ 30 декабря 2010

Мой поисковик работает очень хорошо, однако он, как правило, возвращает устаревшие результаты.Мой сайт очень похож на 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

Обратите внимание, что у меня есть индекс "date", в котором хранится дата события.

Мой поиск тогда выглядит следующим образом

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

Я также нашел следующую документацию, но я не могу сделать из нее головы или хвосты
http://lucene.apache.org/java/1_4_3/api/org/apache/lucene/search/DateFilter.html

Ответы [ 2 ]

10 голосов
/ 30 декабря 2010

Вы ссылаетесь на документацию API Lucene 1.4.3. Lucene.Net в настоящее время на 2.9.2. Я думаю, что обновление должно.

Во-первых, вы используете Store. Да, много. Сохраненные поля увеличат ваш индекс, что может быть проблемой производительности. Ваша проблема с датами может быть легко решена путем сохранения дат в виде строк в формате «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, но это также повлияет на оценку (которая рассчитывается по запросу, а не по фильтру). Вы также можете избежать модификации запроса для простоты, чтобы вы знали, какой запрос выполняется.

7 голосов
/ 30 декабря 2010

Вы можете объединить несколько запросов с 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...