2011-01-21 2 views
3

Существует несколько перегрузок метода IndexSearcher.Search в Lucene. Некоторые из них требуют аргументов «top n hits», некоторые - нет (они устарели и будут удалены в Lucene.NET 3.0).Как искать Lucene.NET без указания предела «top n»?

Те, которые требуют аргумента «top n», фактически вызывают предварительное распределение памяти для всего этого возможного диапазона результатов. Поэтому, когда вы находитесь в ситуации, когда вы не можете даже приблизиться к оценке количества возвращенных результатов, единственная возможность - передать случайное большое количество, чтобы гарантировать, что все результаты запроса будут возвращены. Это вызывает сильное давление в памяти и утечки из-за фрагментации LOH.

Есть ли неофициальный не устаревший способ поиска без прохождения аргумента «top n»?

Заранее спасибо, ребята.

ответ

2

Я использую Lucene.NET 2.9.2 в качестве контрольной точки для этого ответа.

Вы можете создать пользовательский коллекционер, который вы перейдете к одной из перегрузок поиска.

using System; 
using System.Collections.Generic; 
using Lucene.Net.Index; 
using Lucene.Net.Search; 

public class AwesomeCollector : Collector { 
    private readonly List<Int32> _docIds = new List<Int32>(); 
    private Scorer _scorer; 
    private Int32 _docBase; 

    public IEnumerable<Int32> DocumentIds { 
     get { return _docIds; } 
    } 

    public override void SetScorer(Scorer scorer) { 
     _scorer = scorer; 
    } 

    public override void Collect(Int32 doc) { 
     var score = _scorer.Score(); 
     if (_lowerInclusiveScore <= score) 
      _docIds.Add(_docBase + doc); 
    } 

    public override void SetNextReader(IndexReader reader, Int32 docBase) { 
     _docBase = docBase; 
    } 

    public override bool AcceptsDocsOutOfOrder() { 
     return true; 
    } 
} 
+0

Благодарим за предложение. Фактически мы используем Collector почти так же, с единственной разницей в использовании LinkedList вместо List, чтобы предотвратить перераспределение памяти при росте. Этот подход отлично работает, когда нет необходимости выполнять сортировку. Нет перегрузки Search(), которая получает как объекты Collector, так и Sort. При использовании параметра «Сортировка» мы вынуждаем Lucene использовать TopHitsCollector по умолчанию, который предопределяет память описанным образом. Возможно, было бы неплохо использовать пользовательский коллекционер, который делает свою собственную сортировку по вызову Coolect. Как вы думаете? –

+0

Я бы изменил его на хранение как идентификатора документа, так и значения сортировки в списке, и выполните сортировку, когда будут собраны все результаты. Вы можете использовать FieldCache, если в поле сортировки есть одно поле ключевого слова, оно будет загружать (и кешировать) значения полей для каждого сегмента. Вы должны использовать внутренний читатель (тот, который вам передал в SetNextReader), чтобы кеш работал правильно. – sisve

+0

Да, я думаю, это был бы лучший способ сделать это, за исключением использования кеша поля. Эта вещь поглощает много памяти в большом индексе, и, поскольку мы должны повторно открывать ее довольно часто, я бы предпочел не загружать все данные поля из индекса в память только ради сортировки нескольких сотен строк. Поэтому кажется, что ваш совет в основном является ответом на мой вопрос. Спасибо Simon :) –

Смежные вопросы