BooleanQuery $ toomanyclaUses Exceção ao usar consultas curinga
-
21-09-2019 - |
Pergunta
Estou usando o Hibernate Search / Lucene para manter um índice realmente simples para encontrar objetos pelo nome - sem coisas sofisticadas.
Minhas aulas de modelo estendem uma aula NamedModel
que parece basicamente o seguinte:
@MappedSuperclass
public abstract class NamedModel {
@Column(unique = true)
@Field(store = Store.YES, index = Index.UN_TOKENIZED)
protected String name;
}
Meu problema é que eu recebo um BooleanQuery$TooManyClauses
exceção ao consultar o índice para objetos com nomes começando com uma carta específica, por exemplo "name:l*"
. Uma consulta como "name:lin*"
Funcionará sem problemas, de fato, qualquer consulta usando mais de uma letra antes do curinga funcionará.
Ao pesquisar na rede por problemas semelhantes, só encontrei pessoas usando consultas bastante complexas e isso sempre parecia causar a exceção. Eu não quero aumentar maxClauseCount
Porque não acho que seja uma boa prática mudar de limites apenas porque você os alcança.
Qual é o problema aqui?
Solução
Lucene tenta reescrever sua consulta de simples name:l*
para uma consulta com todos os termos começando com L neles (algo como name:lou OR name:la OR name: ...
) - Acredito que isso deve ser mais rápido.
Como solução alternativa, você pode usar um ConstantScorePrefixQuery
em vez de um PrefixQuery
:
// instead of new PrefixQuery(prefix)
new ConstantScoreQuery(new PrefixFilter(prefix));
No entanto, isso muda a pontuação dos documentos (daí a classificação se você confiar na pontuação para classificar). Enquanto enfrentamos o desafio de precisar de pontuação (e Boost), decidimos optar por uma solução onde usamos PrefixQuery
Se possível e fallback para ConstantScorePrefixQuery
onde necessário:
new PrefixQuery(prefix) {
public Query rewrite(final IndexReader reader) throws IOException {
try {
return super.rewrite(reader);
} catch (final TooManyClauses e) {
log.debug("falling back to ConstantScoreQuery for prefix " + prefix + " (" + e + ")");
final Query q = new ConstantScoreQuery(new PrefixFilter(prefix));
q.setBoost(getBoost());
return q;
}
}
};
(Como aprimoramento, alguém poderia usar algum tipo de LRUMap
Para armazenar os termos que falharam antes de evitar passar por uma reescrita dispendiosa novamente)
Não posso ajudá -lo a integrar isso na pesquisa de hibernação. Você pode perguntar depois que mudou para Bússola ;)