org.apache.lucene.search.BooleanQuery$TooManyClauses: maxClauseCount is set to 1024
Esto normalmente viene provocado por hacer una consulta con carácteres comodines (* y ?). Cuando hacemos una consulta de este tipo, WildcardQuery, lo que hace internamente Lucene es sustituir nuestra consulta con comodines por una consulta sin ellos. ¿Cómo? Pues mira los campos que cumplan el patrón de la consulta y hace un OR con cada uno de ellos.
Mejor veamos un ejemplo:
Supongamos que tenemos indexado documentos y queremos encontrar todos aquellos cuyo campo título empiece por "cas". Para ello haremos la siguiente consulta:
titulo: cas*
Al tratarse de una WildcardQuery, Lucene miraría en todos los campos "titulo" del índice y tomaría aquellos que empiezan por "cas", por ejemplo supongamos que existen 3: "casa", "casita" y "caserio". Lucene sustituiría la consulta por:
titulo: casa or titulo: casita or titulo: caserio
En este ejemplo, vemos que una simple consulta que para mí tiene únicamente una única clausula, realmente se convierte en una consulta con 3 clausulas. Si en lugar de existir sólo 3 campos "titulo" que empiecen por "cas" existieran más de 1024, nos daría el error que he comentado al principio.
Conclusión: no usar comodines. Por desgracia, esto no es siempre posible, pero si se piensa un poco a la hora de indexar, sí que podemos minimizar los casos de uso de las WildcardQuerys.
Indexar una estructura de carpetas o en árbol
Es muy corriente el uso de Lucene para indexar estructuras en árbol como un sistema de ficheros en un gestor de contenidos. Cuando se tiene una estructura en árbol se usa mucho la consulta por ruta o path. Supongamos que tenemos una carpeta A, que dentro tiene otra, B y ésta a su vez tiene otra, C. A su vez cada carpeta tiene ficheros dentro. La ruta hacia C sería /A/B/C y la de cualquier fichero en C /A/B/C/nombre_fichero.
Es lógico indexar en cada Document de Lucene un campo llamado path que contenga la ruta. De esta forma, podemos buscar un contenido por ruta:
path: /A/B/C/nombre_fichero
o buscar los hijos de C (todos los que su ruta empiece por la de C)
path: /A/B/C/*
Dependiendo de los hijos que tenga C, podremos superar el maxClauseCount. Y lo más seguro es que tarde o temprano lo hagamos.
Para evitar este problema, lo que podemos hacer es:
- Seguimos indexando el campo path para hacer consultas por ruta pero sin *.
- Indexamos la ruta de la carpeta padre, por ejemplo en el campo parent_path. Esto nos servirá para consultar los hijos de una carpeta.
- Indexamos como campo múltiple la ruta de todas las carpetas padres. Por ejemplo, llamemosle ancestor_path. Esto nos sirve para buscar los hijos, nietos, bisnietos,.... de una carpeta.
Dicho esto, para el fichero /A/B/C/nombre_fichero, indexaríamos lo siguiente:
- path: /A/B/C/nombre_fichero
- parent_path: /A/B/C
- ancestor_path: /A
- ancestor_path: /A/B
- ancestor_path: /A/B/C
Si queremos obtener un contenido a partir de su ruta, la consulta seguiría siendo la misma:
path: /A/B/C/nombre_fichero
pero si queremos obtener los hijos de C ya no tenemos que usar comodines:
parent_path: /A/B/C
y si quisieramos obtener todos los hijos de A, incluido nietos tampoco:
ancestor_path: /A
De esta forma, estamos evitando el error del maxClauseCount en este tipo de consultas, que por otro lado suelen ser muy habituales si se trabaja sobre una estructura en árbol.
Si vuestro caso es otro, quizás pensando un poco podáis encontrar una solución alternativa a los comodines. Y si no, no tendréis más remedio que aumentar el maxClauseCount, pero como se suele decir, "eso es pan para hoy, pero hambre para mañana".
Por último, decir que en Lucene no van bien las consultas con "/", por lo que tendréis que transformar el path antes de indexar y antes de consultar, de forma que sustituyáis las "/" por otro/s caráctere/s. Podéis usar las solución que hace Alfresco, que consiste en transformar las "/" por "_x" o algo así. Es una ISO, pero no recuerdo el número. En cuanto lo encuentre lo actualizaré.
Espero que os sea de utilidad.