Более быстрый способ получить отличные значения от Lucene Query

StackOverflow https://stackoverflow.com/questions/618227

  •  03-07-2019
  •  | 
  •  

Вопрос

В настоящее время мне нравится это:

IndexSearcher searcher = new IndexSearcher(lucenePath);
Hits hits = searcher.Search(query);
Document doc;
List<string> companyNames = new List<string>();

for (int i = 0; i < hits.Length(); i++)
{
    doc = hits.Doc(i);
    companyNames.Add(doc.Get("companyName"));
}
searcher.Close();

companyNames = companyNames.Distinct<string>().Skip(offSet ?? 0).ToList();
return companyNames.Take(count??companyNames.Count()).ToList();

Как видите, я сначала собираю ВСЕ поля (несколько тысяч), а затем различаю их, возможно, пропускаю некоторые и вынимаю некоторые.

Я чувствую, что должен быть лучший способ сделать это.

Это было полезно?

Решение

Честно говоря, я не уверен, что Lucene не предоставляет «отличных» функций. Я полагаю, что с помощью SOLR вы можете использовать поиск фасетов для достижения этой цели, но если вы хотите этого в Lucene, вам придется самостоятельно написать какую-то функциональность фасетов. Поэтому, если вы не столкнетесь с проблемами производительности, с этим все будет в порядке.

Другие советы

Связывая этот вопрос с более ранним вашим вопросом (re: " Слишком много статей "), я думаю, вам определенно следует взглянуть на перечисление терминов из программы чтения индекса. Кэшируйте результаты (я использовал отсортированный словарь с ключом по имени поля, со списком терминов в качестве данных, максимум до 100 терминов на поле), пока читатель индекса не станет недействительным, и вы уйдете.

Или, может быть, я должен сказать, что когда я столкнулся с проблемой, подобной вашей, это я и сделал.

Надеюсь, это поможет,

Я предлагаю вам найти логику, чтобы пропустить этот тип итерации, но если в вашем контексте нет решения, вы можете получить выигрыш в производительности с помощью следующего кода
1) во время индекса лучше всего поместить поле, которое вы хотите перебрать, в первое поле

Document doc = new Document();
Field companyField = new Field(...);
doc.Add(companyField);
...

2) тогда вам нужно определить FieldSelector следующим образом

class CompanyNameFieldSelector : FieldSelector
{
    public FieldSelectorResult Accept(string fieldName)
    {
        return (fieldName == "companyName" ? FieldSelectorResult.LOAD_AND_BREAK : FieldSelectorResult.NO_LOAD);
    }
}

3) Затем, когда вы хотите повторить и выбрать это поле, вы должны сделать что-то вроде этого

FieldSelector companySelector = new CompanyNameFieldSelector();
// when you iterate through your index
doc = hits.Doc(i);
doc.Get("companyName", companySelector);

Производительность приведенного выше кода намного выше, чем у предоставленного вами кода, поскольку он пропускает чтение ненужных полей документа и экономит время.

public List<string> GetDistinctTermList(string fieldName)
    {
        List<string> list = new List<string>();

        using (IndexReader reader = idxWriter.GetReader())
        {
            TermEnum te = reader.Terms(new Term(fieldName));

            if (te != null && te.Term != null && te.Term.Field == fieldName)
            {
                list.Add(te.Term.Text);

                while (te.Next())
                {
                    if (te.Term.Field != fieldName)
                        break;
                    list.Add(te.Term.Text);
                }
            }
        }

        return list;
    }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top