maneira mais rápida de obter valores distintos a partir Lucene consulta

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

  •  03-07-2019
  •  | 
  •  

Pergunta

Atualmente eu faço assim:

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

Como você pode ver, eu primeiro recolher todos os campos (vários milhares) e depois distinta deles, possivelmente ignorar alguns e levar algum fora.

Eu sinto que deve haver uma maneira melhor de fazer isso.

Foi útil?

Solução

Eu não tenho certeza que existe, honestamente, como Lucene não fornece funcionalidade 'distinta'. Eu acredito com SOLR você pode usar uma pesquisa faceta de conseguir isso, mas se você quer este em Lucene, você teria que escrever algum tipo de funcionalidade faceta si mesmo. Então, enquanto você não correr em quaisquer problemas de desempenho, você deve estar ok desta forma.

Outras dicas

Amarrar esta questão a uma pergunta anterior de sua (re: "Muitas cláusulas"), eu acho que você definitivamente deveria estar olhando para enumeração termo do leitor índice. Cache os resultados (eu usei um ordenado dicionário com chave no nome do campo, com uma lista de termos como os dados, a um máximo de 100 termos por campo) até que o leitor índice torna-se inválido e você vai longe.

Ou talvez eu devesse dizer que, quando confrontados com um problema semelhante ao seu, que é o que eu fiz.

Espero que isso ajude,

Eu sugiro que você para encontrar uma lógica para ignorar este tipo de iteração, mas se não houver uma solução em sua contexto, então você pode obter um ganho de desempenho com o seguinte código
1) no tempo Index é melhor colocar o campo que deseja iterate, no primeiro campo

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

2), então você precisa definir um FieldSelector como este

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

3) Então, quando você quer iterate e escolher neste campo você deve fazer algo assim

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

O desempenho do código acima é muito melhor do que o código que você forneceu porque é pular lendo campos de documentos desnecessários e economizar tempo.

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;
    }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top