Existen tres clasificaciones principales de consultas lentas en AEM, enumeradas por gravedad:
Consultas sin índice
Consultas poco restringidas (o con ámbito)
Consultas de conjuntos de resultados grandes
Las dos primeras clasificaciones de consultas (sin índice y mal restringidas) son lentas, porque obligan al motor de consulta Oak a inspeccionar cada resultado potencial (nodo de contenido o entrada de índice) para identificar qué pertenece al conjunto de resultados real.
El acto de inspeccionar cada posible resultado es lo que se conoce como Traversing.
Dado que debe inspeccionarse cada posible resultado, el costo para determinar el resultado real crece de manera lineal con el número de posibles resultados.
Añadir las restricciones de consulta y los índices de ajuste permite almacenar los datos del índice en un formato optimizado que permite una rápida recuperación de los resultados y reduce o elimina la necesidad de realizar una inspección lineal de los posibles conjuntos de resultados.
En AEM 6.3, de forma predeterminada, cuando se alcanza un recorrido de 100.000, la consulta falla y emite una excepción. Este límite no existe de forma predeterminada en las versiones AEM anteriores a AEM 6.3, pero se puede establecer mediante la configuración OSGi de Apache Jackrabbit Engine y el grano JMX QueryEngineSettings (propiedad LimitReads).
Explicar todas consultas y asegurarse de que sus planes de consulta no contengan la /* explicación de traverse en ellos. Ejemplo de plan de consulta de recorrido:
[nt:unstructured] as [a] /* traverse "/content//*" where ([a].[unindexedProperty] = 'some value') and (isdescendantnode([a], [/content])) */
Monitoree el error.log
para consultas de recorrido sin índice:
*INFO* org.apache.jackrabbit.oak.query.QueryImpl Traversal query (query without index) ... ; consider creating and index
Visite la consola de operaciones Rendimiento de Consulta de AEM y Explicar consultas lentas que buscan explicaciones de consulta de índice o de recorrido.
Explicar todas las consultas y asegurarse de que se resuelven en un índice ajustado para coincidir con las restricciones de propiedad de la consulta.
indexRules
para todas las restricciones de propiedad y, como mínimo, para las restricciones de propiedad más estrictas de la consulta.orderable=true.
cqPageLucene
predeterminado no tiene una regla de índice para jcr:content/cq:tags
Antes de agregar la regla de índice cq:tags
cq:regla de índice de etiquetas
Consulta consulta Builder
type=cq:Page
property=jcr:content/cq:tags
property.value=my:tag
Plan de consulta
[cq:Page] as [a] /* lucene:cqPageLucene(/oak:index/cqPageLucene?lang=es) *:* where [a].[jcr:content/cq:tags] = 'my:tag' */
Esta consulta se resuelve en el índice cqPageLucene
, pero como no existe ninguna regla de índice de propiedad para jcr:content
o cq:tags
, cuando se evalúa esta restricción, todos los registros del índice cqPageLucene
se comprueban para determinar una coincidencia. Esto significa que si el índice contiene 1 millón de nodos cq:Page
, entonces se verifican 1 millón de registros para determinar el conjunto de resultados.
Después de agregar la regla de índice cq:tags
cq:regla de índice de etiquetas
/oak:index/cqPageLucene/indexRules/cq:Page/properties/cqTags
@name=jcr:content/cq:tags
@propertyIndex=true
Consulta consulta Builder
type=cq:Page
property=jcr:content/cq:tags
property.value=myTagNamespace:myTag
Plan de consulta
[cq:Page] as [a] /* lucene:cqPageLucene(/oak:index/cqPageLucene?lang=es) jcr:content/cq:tags:my:tag where [a].[jcr:content/cq:tags] = 'my:tag' */
La adición de indexRule para jcr:content/cq:tags
en el índice cqPageLucene
permite que los datos cq:tags
se almacenen de manera optimizada.
Cuando se realiza una consulta con la restricción jcr:content/cq:tags
, el índice puede buscar los resultados por valor. Esto significa que si 100 cq:Page
nodos tienen myTagNamespace:myTag
como valor, sólo se devuelven esos 100 resultados y los otros 999.000 se excluyen de las comprobaciones de restricción, lo que mejora el rendimiento en un factor de 10.000.
Por supuesto, las restricciones de consulta adicionales reducen los conjuntos de resultados elegibles y optimizan aún más la optimización de la consulta.
De manera similar, sin una regla de índice adicional para la propiedad cq:tags
, incluso una consulta de texto completo con una restricción en cq:tags
tendría un mal rendimiento, ya que los resultados del índice devolverían todas las coincidencias de texto completo. La restricción de las etiquetas cq:se filtraría después.
Otra causa del filtrado posterior al índice son las Listas de Control de acceso, que a menudo se pierden durante el desarrollo. Intente asegurarse de que la consulta no devuelve rutas de acceso inaccesibles para el usuario. Esto generalmente se puede hacer mediante una mejor estructura de contenido y proporcionando una restricción de ruta relevante en la consulta.
Una manera útil de identificar si el índice Lucene devuelve muchos resultados para devolver un subconjunto muy pequeño como resultado de la consulta es habilitar los registros DEBUG para org.apache.jackrabbit.oak.plugins.index.lucene.LucenePropertyIndex
y ver cuántos documentos se cargan desde el índice. El número de resultados finales frente al número de documentos cargados no debería ser desproporcionado. Para obtener más información, consulte Registro.
Monitoree el error.log
para consultas transversales:
*WARN* org.apache.jackrabbit.oak.spi.query.Cursors$TraversingCursor Traversed ### nodes ... consider creating an index or changing the query
Visite la consola de operaciones Rendimiento de Consulta de AEM y Explicar consultas lentas que buscan planes de consulta que no resuelvan las restricciones de propiedades de consulta a las reglas de propiedades de índice.
Establezca umbrales bajos para oak.queryLimitInMemory (p. ej. 10000) y oak.queryLimitReads (p. ej. 5000) y optimice la consulta costosa al visitar una excepción UnsupportedOperationException que dice "La consulta lee más de nodos x…".
Esto ayuda a evitar consultas que requieren muchos recursos (por ejemplo: no está respaldada por ningún índice o está respaldada por un índice de cobertura menos elevado). Por ejemplo, una consulta que lee nodos 1M produciría muchas E/S y tendría un impacto negativo en el rendimiento general de la aplicación. Por lo tanto, cualquier consulta que falle debido a los límites superiores debe analizarse y optimizarse.
Monitoree los registros de consultas que activan el consumo de memoria traversal de nodos grandes o de gran consumo de memoria de pila:
*WARN* ... java.lang.UnsupportedOperationException: The query read or traversed more than 100000 nodes. To avoid affecting other tasks, processing was stopped.
Monitoree los registros de consultas que activan el consumo de memoria de gran pila:
*WARN* ... java.lang.UnsupportedOperationException: The query read more than 500000 nodes in memory. To avoid running out of memory, processing was stopped
Para las versiones de AEM 6.0 a 6.2, puede ajustar el umbral para el recorrido de nodos mediante parámetros JVM en la secuencia de comandos de inicio de AEM para evitar que grandes consultas sobrecarguen el entorno. Los valores recomendados son:
-Doak.queryLimitInMemory=500000
-Doak.queryLimitReads=100000
En AEM 6.3, los 2 parámetros anteriores están preconfigurados de forma predeterminada y se pueden modificar mediante OSGi QueryEngineSettings.
Más información disponible en : https://jackrabbit.apache.org/oak/docs/query/query-engine.html#Slow_Queries_and_Read_Limits
El lema de la optimización del rendimiento de consulta en AEM es:
"Cuantas más restricciones, mejor".
A continuación se describen los ajustes recomendados para garantizar el rendimiento de la consulta. Ajuste primero la consulta, una actividad menos complicada y, si es necesario, ajuste las definiciones de índice.
AEM admite los siguientes idiomas de consulta:
En el siguiente ejemplo se utiliza Consulta Builder ya que es el lenguaje de consulta más común utilizado por los desarrolladores de AEM; sin embargo, los mismos principios se aplican a JCR-SQL2 y XPath.
Añada una restricción nodetype para que la consulta se resuelva en un índice de propiedades Lucene existente.
Consulta no optimizada
property=jcr:content/contentType
property.value=article-page
Consulta optimizada
type=cq:Page
property=jcr:content/contentType
property.value=article-page
Las consultas que carecen de una restricción de tipo de nodo obligan a AEM a asumir el tipo de nodo nt:base
, que cada nodo de AEM es un subtipo de, lo que resulta en una restricción de tipo de nodo.
La configuración type=cq:Page
restringe esta consulta sólo a cq:Page
nodos y resuelve la consulta a AEM cqPageLucene, limitando los resultados a un subconjunto de nodos (sólo cq:Page
nodos) en AEM.
Ajuste la restricción nodetype de la consulta para que la consulta se resuelva en un índice de propiedades Lucene existente.
Consulta no optimizada
type=nt:hierarchyNode
property=jcr:content/contentType
property.value=article-page
Consulta optimizada
type=cq:Page
property=jcr:content/contentType
property.value=article-page
nt:hierarchyNode
es el tipo de nodo principal de cq:Page
y, suponiendo que solo jcr:content/contentType=article-page
se aplique a cq:Page
los nodos a través de nuestra aplicación personalizada, esta consulta sólo devolverá cq:Page
nodos donde jcr:content/contentType=article-page
. Sin embargo, esta es una restricción subóptima porque:
nt:hierarchyNode
(p. ej. dam:Asset
) añadiendo innecesariamente al conjunto de posibles resultados.nt:hierarchyNode
, pero sí un índice proporcionado para cq:Page
.La configuración type=cq:Page
restringe esta consulta a sólo nodos cq:Page
y resuelve la consulta a AEM cqPageLucene, limitando los resultados a un subconjunto de nodos (sólo nodos cq:Page) en AEM.
O bien, ajuste las restricciones de propiedad para que la consulta se resuelva en un índice de propiedades existente.
Consulta no optimizada
property=jcr:content/contentType
property.value=article-page
Consulta optimizada
property=jcr:content/sling:resourceType
property.value=my-site/components/structure/article-page
Si se cambia la restricción de propiedad de jcr:content/contentType
(un valor personalizado) a la propiedad conocida sling:resourceType
, la consulta puede resolver el índice de propiedad slingResourceType
que indexa todo el contenido por sling:resourceType
.
Los índices de propiedades (a diferencia de los índices de propiedades de Lucene) se utilizan mejor cuando la consulta no se detecta por tipo de nodo y una única restricción de propiedad domina el conjunto de resultados.
Añada la restricción de ruta más estricta posible para la consulta. Por ejemplo, prefiera /content/my-site/us/en
por encima de /content/my-site
o /content/dam
por encima de /
.
Consulta no optimizada
type=cq:Page
path=/content
property=jcr:content/contentType
property.value=article-page
Consulta optimizada
type=cq:Page
path=/content/my-site/us/en
property=jcr:content/contentType
property.value=article-page
Al establecer la restricción de ruta de path=/content
a path=/content/my-site/us/en
, los índices pueden reducir el número de entradas de índice que se deben inspeccionar. Cuando la consulta puede restringir la ruta muy bien, más allá de /content
o /content/dam
, asegúrese de que el índice tenga evaluatePathRestrictions=true
.
Tenga en cuenta que el uso de evaluatePathRestrictions
aumenta el tamaño del índice.
Cuando sea posible, evite las funciones y operaciones de consulta, como: LIKE
y fn:XXXX
a medida que sus costos escalan con el número de resultados basados en restricciones.
Consulta no optimizada
type=cq:Page
property=jcr:content/contentType
property.operation=like
property.value=%article%
Consulta optimizada
type=cq:Page
fulltext=article
fulltext.relPath=jcr:content/contentType
La condición LIKE es lenta de evaluar porque no se puede utilizar ningún índice si el texto está inicio con un comodín ("%…'). La condición jcr:contains permite utilizar un índice de texto completo y, por lo tanto, es preferible. Esto requiere que el Índice de propiedades de Lucene resuelto tenga indexRule para jcr:content/contentType
con analayzed=true
.
El uso de funciones de consulta como fn:lowercase(..)
puede resultar más difícil de optimizar, ya que no hay equivalentes más rápidos (fuera de configuraciones de analizador de índices más complejas y obtrusivas). Lo mejor es identificar otras restricciones de creación de ámbitos para mejorar el rendimiento general de la consulta, lo que requiere que las funciones funcionen en el conjunto más pequeño posible de resultados potenciales.
Este ajuste es específico del Generador de Consultas y no se aplica a JCR-SQL2 o XPath.
Utilice generador de Consultas 'adivinenTotal cuando el conjunto completo de resultados sea no inmediatamente necesario.
Consulta no optimizada
type=cq:Page
path=/content
Consulta optimizada
type=cq:Page
path=/content
p.guessTotal=100
En los casos en los que la ejecución de la consulta es rápida pero el número de resultados es grande, p. guessTotal
es una optimización crítica para las consultas del Generador de Consultas.
p.guessTotal=100
indica a Consulta Builder que solo recopile los primeros 100 resultados y defina un indicador booleano que indique si existen al menos otros resultados (pero no cuántos más, ya que contar este número sería lento). Esta optimización destaca para los casos de uso de paginación o carga infinita, donde sólo se muestra un subconjunto de resultados de forma incremental.
Si la consulta óptima se resuelve en un índice de propiedades, no queda nada por hacer, ya que los índices de propiedades pueden ajustarse de forma mínima.
De lo contrario, la consulta debería resolver en un índice de propiedades de Lucene. Si no se puede resolver ningún índice, vaya a Creación de un nuevo índice.
Si es necesario, convierta la consulta a XPath o JCR-SQL2.
Consulta consulta Builder
query type=cq:Page
path=/content/my-site/us/en
property=jcr:content/contentType
property.value=article-page
orderby=@jcr:content/publishDate
orderby.sort=desc
XPath generado a partir de la consulta del Generador de Consultas
/jcr:root/content/my-site/us/en//element(*, cq:Page)[jcr:content/@contentType = 'article-page'] order by jcr:content/@publishDate descending
Proporcione XPath (o JCR-SQL2) a Generador de definiciones de índices Oak para generar la definición optimizada del índice de propiedades de Lucene.
Definición del índice de propiedades de Lucene generada
- evaluatePathRestrictions = true
- compatVersion = 2
- type = "lucene"
- async = "async"
- jcr:primaryType = oak:QueryIndexDefinition
+ indexRules
+ cq:Page
+ properties
+ contentType
- name = "jcr:content/contentType"
- propertyIndex = true
+ publishDate
- ordered = true
- name = "jcr:content/publishDate"
Combine manualmente la definición generada con el Índice de propiedades de Lucene existente de forma aditiva. Tenga cuidado de no eliminar las configuraciones existentes, ya que pueden utilizarse para satisfacer otras consultas.
/oak:index/cqPageLucene
.Compruebe que la consulta no se resuelve en un índice de propiedades de Lucene existente. Si es así, consulte la sección anterior sobre ajuste e índice existente.
Si es necesario, convierta la consulta a XPath o JCR-SQL2.
Consulta consulta Builder
type=myApp:Author
property=firstName
property.value=ira
XPath generado a partir de la consulta del Generador de Consultas
//element(*, myApp:Page)[@firstName = 'ira']
Proporcione XPath (o JCR-SQL2) a Generador de definiciones de índices Oak para generar la definición optimizada del índice de propiedades de Lucene.
Definición del índice de propiedades de Lucene generada
- compatVersion = 2
- type = "lucene"
- async = "async"
- jcr:primaryType = oak:QueryIndexDefinition
+ indexRules
+ myApp:AuthorModel
+ properties
+ firstName
- name = "firstName"
- propertyIndex = true
Implemente la definición generada del índice de propiedades de Lucene.
Añada la definición XML proporcionada por Oak Index Definition Generator para el nuevo índice al proyecto de AEM que administra las definiciones de índice Oak (recuerde, trate las definiciones de índice Oak como código, ya que el código depende de ellas).
Implemente y pruebe el nuevo índice siguiendo el ciclo de vida habitual de desarrollo de software de AEM y verifique que la consulta se resuelva en el índice y que la consulta funcione.
Tras la implementación inicial de este índice, AEM rellenará el índice con los datos necesarios.
Debido a AEM arquitectura de contenido flexible, es difícil predecir y asegurar que las transversales de las estructuras de contenido no evolucionen con el tiempo para ser inaceptablemente grandes.
Por lo tanto, asegúrese de que los índices cumplen las consultas, excepto si la combinación de restricción de ruta y restricción de tipo de nodo garantiza que menos de 20 nodos se hayan recorrido nunca.
Consulta Builder Debugger
CRXDE Lite - Herramienta Consulta
Registro de consulta Builder
DEBUG @ com.day.cq.search.impl.builder.QueryImpl
Registro de ejecución de consultas Oak
DEBUG @ org.apache.jackrabbit.oak.query
Configuración del motor de Consulta Apache Jackrabbit Configuración OSGi
NodoContador de granos JMX
Generador de definiciones de índice Oak