Evite "muitas cláusulas" na consulta Lucene
-
03-07-2019 - |
Pergunta
Nos meus testes, de repente encontrei uma exceção de muitas cláusulas ao tentar obter os hits de uma consulta booleana que consistia em um TermQuery e uma consulta curinga.
Eu procurei pela rede e com os recursos encontrados que eles sugerem para aumentar o booleanQuery.setMaxclaUseCount ().
Isso me parece suspeito .. para o que devo melhorar? Como posso confiar que esse novo número mágico será suficiente para minha consulta? Até onde posso incrementar esse número antes que todo o inferno se solte?
Em geral, sinto que isso não é uma solução. Deve haver um problema mais profundo ..
A consulta foi +{ +CompanyName: Mercedes +PaintCode: A*} e o índice possui ~ 2,5m documentos.
Solução
O PaintCode: A* Parte da consulta é uma consulta de prefixo para qualquer código de tinta que começa com um "A". É isso que você está buscando?
O Lucene expande consultas de prefixo em uma consulta booleana contendo todos os termos possíveis que correspondem ao prefixo. No seu caso, aparentemente existem mais de 1024 possíveis paintCode
S que começam com um "A".
Se parecer que você gosta de consultas de prefixo é inútil, você não está longe da verdade.
Eu sugiro que você altere seu esquema de indexação para evitar o uso de uma consulta de prefixo. Não tenho certeza do que você está tentando realizar com o seu exemplo, mas se você deseja procurar códigos de pintura pela primeira letra, faça um campo PaintCodeFirstletter e pesquise nesse campo.
ADICIONADO
Se você estiver desesperado e está disposto a aceitar resultados parciais, pode criar sua própria versão do Lucene a partir da fonte. Você precisa fazer alterações nos arquivos PrefixQuery.java
e MultiTermQuery.java
, ambos abaixo org/apache/lucene/search
. No rewrite
Método de ambas as classes, mude a linha
query.add(tq, BooleanClause.Occur.SHOULD); // add to query
para
try {
query.add(tq, BooleanClause.Occur.SHOULD); // add to query
} catch (TooManyClauses e) {
break;
}
Eu fiz isso para o meu próprio projeto e funciona.
Se você realmente não gosta da ideia de mudar o Lucene, pode escrever sua própria variante de prefixija e seu próprio QueryParser, mas não acho que seja muito melhor.
Outras dicas
Parece que você está usando isso em um campo que é uma espécie de Palavra -chave Tipo (o que significa que não haverá vários tokens no seu campo de fonte de dados).
Há uma sugestão aqui que me parece bastante elegante: http://grokbase.com/t/lucene.apache.org/java-user/2007/11/substring-indexing-to-avoid-toomanyclaus-exception/12f7s7kzp2emktbn66tdmfpcxfya
A idéia básica é dividir seu termo em vários campos com um comprimento crescente até ter certeza de que não atingirá o limite da cláusula.
Exemplo:
Imagine um código de tinta como este:
"a4c2d3"
Ao indexar esse valor, você cria os seguintes valores de campo em seu documento:
[paintCode]: "a4c2d3"
[paintCode1n]: "a"
[paintCode2n]: "a4"
[paintCode3n]: "a4c"
Quando você consultar, o número de caracteres em seu termo decidir em qual campo pesquisar. Isso significa que você realizará uma consulta de prefixo só Para termos com mais de 3 caracteres, o que diminui bastante a contagem de resultados internos, impedindo o infame ToomanyBooleanclaUsesexception. Aparentemente, isso também acelera o processo de pesquisa.
Você pode automatizar facilmente um processo que divide os termos automaticamente e preenche os documentos com valores de acordo com um esquema de nome durante a indexação.
Alguns problemas podem surgir se você tiver vários tokens para cada campo. Você pode encontrar mais detalhes no artigo