AEM En as a Cloud Service, todos los aspectos operativos relacionados con la indexación están automatizados. Esto permite a los desarrolladores centrarse en crear consultas eficientes y sus definiciones de índice correspondientes.
Las consultas son una forma de acceder al contenido, pero no son la única posibilidad. En muchas situaciones, se puede acceder al contenido del repositorio de forma más eficaz por otros medios. Debe tener en cuenta si las consultas son la forma mejor y más eficaz de acceder al contenido para su caso de uso.
Al diseñar la taxonomía de un repositorio, se deben tener en cuenta varios factores. Estos incluyen controles de acceso, localización, herencia de componentes y propiedades de página, etc.
Al diseñar una taxonomía que aborde estas preocupaciones, también es importante tener en cuenta la "transitabilidad" del diseño de indexación. En este contexto, la transitabilidad es la capacidad de una taxonomía para permitir que se acceda al contenido de forma predecible en función de su ruta. Esto ofrece un sistema más eficiente, fácil de mantener, que uno que requiere que se ejecuten varias consultas.
Además, al diseñar una taxonomía, es importante tener en cuenta si la ordenación es importante. En los casos en los que no se requiere un orden explícito y se espera un gran número de nodos hermanos, se prefiere utilizar un tipo de nodo sin ordenar como sling:Folder
o oak:Unstructured
. En los casos en que sea necesario realizar un pedido, nt:unstructured
y sling:OrderedFolder
sería más apropiado.
AEM Dado que las consultas pueden ser una de las operaciones más gravosas realizadas en un sistema de, es aconsejable evitarlas en los componentes. Tener varias consultas ejecutándose cada vez que se procesa una página puede a menudo degradar el rendimiento del sistema. Existen dos estrategias que se pueden utilizar para evitar la ejecución de consultas al procesar componentes: atravesar nodos y recuperación previa de resultados.
Si el repositorio está diseñado de manera que permita un conocimiento previo de la ubicación de los datos necesarios, se puede implementar un código que recupere estos datos de las rutas necesarias sin tener que ejecutar consultas para encontrarlos.
Un ejemplo de esto sería procesar contenido que se ajuste a una categoría determinada. Un método sería organizar el contenido con una propiedad category que se pueda consultar para rellenar un componente que muestre los elementos de una categoría.
Un mejor enfoque sería estructurar este contenido en una taxonomía por categoría para que se pueda recuperar manualmente.
Por ejemplo, si el contenido se almacena en una taxonomía similar a:
/content/myUnstructuredContent/parentCategory/childCategory/contentPiece
el /content/myUnstructuredContent/parentCategory/childCategory
El nodo simplemente se puede recuperar, sus tareas secundarias se pueden analizar y utilizar para procesar el componente.
Además, cuando se trata de un conjunto de resultados pequeño u homogéneo, puede ser más rápido atravesar el repositorio y recopilar los nodos necesarios, en lugar de crear una consulta para devolver el mismo conjunto de resultados. Como consideración general, las consultas deben evitarse siempre que sea posible hacerlo.
A veces, el contenido o los requisitos relacionados con el componente no permiten el uso del recorrido de nodos como método para recuperar los datos necesarios. En estos casos, es necesario ejecutar las consultas necesarias antes de procesar el componente para garantizar un rendimiento óptimo.
Si los resultados necesarios para el componente se pueden calcular en el momento en que se crea y no hay expectativas de que el contenido cambie, la consulta se puede ejecutar después de realizar un cambio.
Si los datos o el contenido cambian con regularidad, la consulta se puede ejecutar en una programación o a través de un oyente para actualizaciones de los datos subyacentes. A continuación, los resultados se pueden escribir en una ubicación compartida del repositorio. Cualquier componente que necesite estos datos puede extraer los valores de este nodo único sin necesidad de ejecutar una consulta en tiempo de ejecución.
Se puede utilizar una estrategia similar para mantener el resultado en una caché en memoria, que se rellena al inicio y se actualiza cada vez que se realizan cambios (con un JCR) ObservationListener
o un Sling ResourceChangeListener
).
La documentación de Oak proporciona una información general de alto nivel sobre cómo se ejecutan las consultas. Esto forma la base de todas las actividades de optimización descritas en este documento.
AEM El as a Cloud Service proporciona el Herramienta de rendimiento de consultas, diseñado para admitir la implementación de consultas eficientes.
Se puede acceder a la herramienta de rendimiento de consultas mediante el Developer Console en Cloud Manager. AEM La herramienta de rendimiento de consultas de as a Cloud Service AEM proporciona más información sobre los detalles de la ejecución de consultas en la versión 6.x de la misma en la que se ejecuta la consulta de la manera más sencilla posible.
Este gráfico ilustra el flujo general para utilizar la herramienta de rendimiento de consultas para optimizar las consultas.
Cada consulta debe utilizar un índice para ofrecer un rendimiento óptimo. En la mayoría de los casos, los índices existentes listos para usar deberían ser suficientes para gestionar consultas.
A veces, es necesario agregar propiedades personalizadas a un índice existente, por lo que se pueden consultar restricciones adicionales mediante el índice. Ver el documento Búsqueda de contenido e indexación para obtener más información. El Hoja de trucos de consulta JCR de este documento describe el aspecto que debe tener una definición de propiedad en un índice para admitir un tipo de consulta específico.
La restricción principal de cualquier consulta debe ser una coincidencia de propiedad, ya que es el tipo más eficaz. Añadir más restricciones de propiedad limita aún más el resultado.
El motor de consultas considera un solo índice. Esto significa que un índice existente puede y debe personalizarse añadiéndole más propiedades de índice personalizadas.
El Hoja de trucos de consulta JCR de este documento enumera las restricciones disponibles y también describe el aspecto que debe tener una definición de índice para que se recoja. Utilice el Herramienta de rendimiento de consultas para probar la consulta y asegurarse de que se utiliza el índice correcto y de que el motor de consultas no necesita evaluar las restricciones fuera del índice.
Si se solicita un orden específico del resultado, el motor de consultas puede hacerlo de dos formas:
ordered=true
en la definición del índice.ordered=true
propiedad.El tamaño recuperado del resultado de la consulta es un factor importante en el rendimiento de la consulta. Como el resultado se obtiene de forma diferida, existe una diferencia entre recuperar los 20 primeros resultados y recuperar 10 000 resultados, tanto en tiempo de ejecución como en uso de memoria.
Esto también significa que el tamaño del conjunto de resultados solo se puede determinar correctamente si se recuperan todos los resultados. Por este motivo, el conjunto de resultados recuperado siempre debe estar limitado, ya sea aumentando la consulta (consulte la Hoja de trucos de consulta JCR de este documento para obtener más información) o limitando las lecturas de los resultados.
Este límite también evita que el motor de consultas visite límite de recorrido de 100 000 nodos, lo que provoca una parada forzada de la consulta.
Consulte la sección Consultas con grandes conjuntos de resultados de este documento si un conjunto de resultados potencialmente grande debe procesarse completamente.
La herramienta de rendimiento de consultas (ubicada en /libs/granite/operations/content/diagnosistools/queryPerformance.html
y disponibles a través de Consola de desarrollador en Cloud Manager) proporciona -
Las tablas "Consultas lentas" y "Consultas populares" incluyen:
Estas tablas ayudan a identificar consultas que no están totalmente indexadas (consulte Uso de un índice o están leyendo demasiados nodos (consulte también Recorrido del repositorio y Índice de recorrido). Estas consultas se resaltarán, con las áreas de preocupación apropiadas marcadas en rojo.
El Reset Statistics
se proporciona la opción para eliminar todas las estadísticas existentes recopiladas en las tablas. Esto permite ejecutar una consulta determinada (a través de la propia aplicación o de la herramienta Explicar consulta) y analizar las estadísticas de ejecución.
La herramienta de consulta Explicar permite a los desarrolladores comprender el plan de ejecución de la consulta (consulte Lectura del Plan de ejecución de consultas), incluidos los detalles de cualquier índice utilizado al ejecutar la consulta. Esto puede utilizarse para comprender la eficacia con la que se indexa una consulta para predecir o analizar de forma retrospectiva su rendimiento.
Para explicar una consulta, haga lo siguiente:
Language
lista desplegable.Query
field.Include Execution Time
: ejecute la consulta pero no intente leer ningún resultado.Read first page of results
: ejecute la consulta y lea la primera "página" de 20 resultados (replicando las prácticas recomendadas para ejecutar consultas).Include Node Count
- ejecutar la consulta y leer el conjunto de resultados completo (generalmente no se recomienda esto: consulte Índice de recorrido).Después de seleccionar Explain
A continuación, se muestra al usuario una ventana emergente que describe el resultado de la explicación de la consulta (y la ejecución, si está seleccionada).
Esta ventana emergente incluye detalles de lo siguiente:
Include Execution Time
casilla de verificación estaba activada) y recuento de resultados leídos (si Read first page of results
o Include Node Count
casillas de verificación marcadas).Read first page of results
casilla de verificación activada)El plan de ejecución de consultas contiene todo lo necesario para predecir (o explicar) el rendimiento de una consulta determinada. Comprenda la eficacia con la que se ejecutará la consulta comparando las restricciones y el orden de la consulta JCR (o Query Builder) original con la consulta ejecutada en el índice subyacente (Lucene, Elastic o Property).
Tenga en cuenta la siguiente consulta:
/jcr:root/content/dam//element(*, dam:Asset) [jcr:content/metadata/dc:title = "My Title"] order by jcr:created
… que contiene -
dam:Asset
)/content/dam
)jcr:content/metadata/dc:title = "My Title"
)jcr:created
propiedadExplicar esta consulta resulta en el siguiente plan:
[dam:Asset] as [a] /* lucene:damAssetLucene-9(/oak:index/damAssetLucene-9) +:ancestors:/content/dam +jcr:content/metadata/dc:title:My Title ordering:[{ propertyName : jcr:created, propertyType : UNDEFINED, order : ASCENDING }] where ([a].[jcr:content/metadata/dc:title] = 'My Title') and (isdescendantnode([a], [/content/dam])) */
Dentro de este plan, la sección que describe la consulta ejecutada en el índice subyacente es -
lucene:damAssetLucene-9(/oak:index/damAssetLucene-9) +:ancestors:/content/dam +jcr:content/metadata/dc:title:My Title ordering:[{ propertyName : jcr:created, propertyType : UNDEFINED, order : ASCENDING }]
Esta sección del plan establece que:
/oak:index/damAssetLucene-9
se utilizarán, por lo que el resto de la información se encuentra en Sintaxis de consultas de Lucene.damAssetLucene-9
solo indexa nodos de tipo dam:Asset.+:ancestors:/content/dam
aparece en la consulta de Lucene.+jcr:content/metadata/dc:title:My Title
aparece en la consulta de Lucene.ordering:[{ propertyName : jcr:created, propertyType : UNDEFINED, order : ASCENDING }]
aparece en la consulta de Lucene.Es probable que una consulta de este tipo funcione bien, ya que los resultados devueltos por la consulta de índice no se filtrarán más en el motor de consultas (aparte del filtrado de Control de acceso). Sin embargo, aún es posible que una consulta de este tipo se ejecute lentamente si no se siguen las prácticas recomendadas: consulte Índice de recorrido más abajo.
Consideración de una consulta diferente:
/jcr:root/content/dam//element(*, dam:Asset) [jcr:content/metadata/myProperty = "My Property Value"] order by jcr:created
… que contiene -
dam:Asset
)/content/dam
)jcr:content/metadata/myProperty = "My Property Value"
)jcr:created
property**Explicar esta consulta resulta en el siguiente plan:
[dam:Asset] as [a] /* lucene:damAssetLucene-9-custom-1(/oak:index/damAssetLucene-9-custom-1) :ancestors:/content/dam ordering:[{ propertyName : jcr:created, propertyType : UNDEFINED, order : ASCENDING }] where ([a].[jcr:content/metadata/myProperty] = 'My Property Value') and (isdescendantnode([a], [/content/dam])) */
Dentro de este plan, la sección que describe la consulta ejecutada en el índice subyacente es -
lucene:damAssetLucene-9(/oak:index/damAssetLucene-9) :ancestors:/content/dam ordering:[{ propertyName : jcr:created, propertyType : UNDEFINED, order : ASCENDING }]
Esta sección del plan establece que:
damAssetLucene-9
solo indexa nodos de tipo dam:Asset.+:ancestors:/content/dam
aparece en la consulta de Lucene.jcr:content/metadata/myProperty = "My Property Value"
no se ejecuta en el índice, sino que se aplica como filtro del motor de consulta a los resultados de la consulta de Lucene subyacente.
+jcr:content/metadata/myProperty:My Property Value
no aparece en la consulta de Lucene, ya que esta propiedad no está indexada en la damAssetLucene-9
índice utilizado para esta consulta.Este plan de ejecución de consultas generará todos los recursos por debajo de /content/dam
leerse desde el índice y, a continuación, filtrarse más por el motor de consultas (que solo incluirá los que coincidan con la restricción de propiedad no indizada en el conjunto de resultados).
Incluso si solo un pequeño porcentaje de recursos coincide con la restricción jcr:content/metadata/myProperty = "My Property Value"
, la consulta debe leer un gran número de nodos para (intentar) rellenar la “página” de resultados solicitada. Esto puede dar como resultado un rendimiento incorrecto de la consulta, que se mostrará como con un bajo Read Optimization
puntuación en la herramienta de rendimiento de consultas) y puede generar mensajes ADVERTENCIA que indiquen que se está atravesando un gran número de nodos (consulte Índice de recorrido).
Para optimizar el rendimiento de esta segunda consulta, cree una versión personalizada de damAssetLucene-9
index (damAssetLucene-9-custom-1
) y agregue la siguiente definición de propiedad:
"myProperty": {
"jcr:primaryType": "nt:unstructured",
"propertyIndex": true,
"name": "jcr:content/metadata/myProperty"
}
Para admitir la creación de consultas JCR y definiciones de índice eficientes, la variable Hoja de características clave de consulta JCR está disponible para su descarga y uso como referencia durante el desarrollo.
Contiene consultas de ejemplo para QueryBuilder, XPath y SQL-2, que cubren varios escenarios que se comportan de forma diferente en términos de rendimiento de la consulta. También proporciona recomendaciones sobre cómo crear o personalizar índices de Oak. AEM El contenido de esta hoja de referencia se aplica a las versiones as a Cloud Service AEM y 6.5 de la.
A continuación se presentan algunas prácticas recomendadas a tener en cuenta al definir o ampliar índices.
dam:Asset
o cq:Page
) prefieren la extensión de los índices OOTB a la adición de nuevos índices.
dam:Asset
no se recomienda utilizar nodetype (consulte esta nota).selectionPolicy = tag
para asegurarse de que el índice solo se utiliza para las consultas deseadas.queryPaths
y includedPaths
se proporcionan ambos (normalmente con los mismos valores).excludedPaths
para excluir rutas que no contendrán resultados útiles.analyzed
propiedades solo cuando es necesario, por ejemplo cuando necesita utilizar una restricción de consulta de texto completo únicamente para esa propiedad.async = [ async, nrt ]
, compatVersion = 2
y evaluatePathRestrictions = true
.nodeScopeIndex = true
si necesita un índice de texto completo de ámbito de nodo.Para obtener más información, consulte Documentación del índice de Oak Lucene.
Las comprobaciones de canalización automatizadas de Cloud Manager aplicarán algunas de las prácticas recomendadas descritas anteriormente.
Aunque se recomienda evitar consultas con grandes conjuntos de resultados, hay casos válidos en los que deben procesarse grandes conjuntos de resultados. A menudo, el tamaño del resultado no se conoce por adelantado, por lo que se deben tomar algunas precauciones para que el procesamiento sea fiable.
Las consultas que atraviesan el repositorio no utilizan un índice y se registran con un mensaje similar al siguiente.
28.06.2022 13:32:52.804 *WARN* [127.0.0.1 [1656415972414] POST /libs/settings/granite/operations/diagnosis/granite_queryperformance.explain.json HTTP/1.1] org.apache.jackrabbit.oak.plugins.index.Cursors$TraversingCursor Traversed 98000 nodes with filter Filter(query=select [jcr:path], [jcr:score], * from [nt:base] as a /* xpath: //* */, path=*) called by com.adobe.granite.queries.impl.explain.query.ExplainQueryServlet.getHeuristics; consider creating an index or changing the query
Con este fragmento de registro puede determinar lo siguiente:
//*
com.adobe.granite.queries.impl.explain.query.ExplainQueryServlet::getHeuristics
para ayudar a identificar al creador de la consulta.Con esta información, es posible optimizar esta consulta utilizando los métodos descritos en la Optimización de consultas de este documento.
Las consultas que utilizan un índice, pero que aún leen grandes cantidades de nodos, se registran con un mensaje similar al siguiente (observe el término Index-Traversed
en lugar de Traversed
).
05.10.2023 10:56:10.498 *WARN* [127.0.0.1 [1696502982443] POST /libs/settings/granite/operations/diagnosis/granite_queryperformance.explain.json HTTP/1.1] org.apache.jackrabbit.oak.plugins.index.search.spi.query.FulltextIndex$FulltextPathCursor Index-Traversed 60000 nodes with filter Filter(query=select [jcr:path], [jcr:score], * from [dam:Asset] as a where isdescendantnode(a, '/content/dam') order by [jcr:content/metadata/unindexedProperty] /* xpath: /jcr:root/content/dam//element(*, dam:Asset) order by jcr:content/metadata/unindexedProperty */, path=/content/dam//*)
Esto puede ocurrir por varias razones:
Causa | Mitigación |
---|---|
La Comisión de p.guessTotal (o el uso de un guessTotal muy grande) que hace que QueryBuilder itere una gran cantidad de resultados contando resultados |
Proporcionar p.guessTotal con un valor apropiado |
El uso de un límite grande o ilimitado en Query Builder (es decir, p.limit=-1 ) |
Use un valor apropiado para p.limit (idealmente 1000 o menos) |
El uso de un predicado de filtrado en el Generador de consultas, que filtra grandes cantidades de resultados de la consulta JCR subyacente | Reemplace los predicados de filtrado por restricciones que se puedan aplicar en la consulta JCR subyacente |
Uso de un orden basado en Comparator en QueryBuilder | Reemplazar por el orden basado en propiedades en la consulta JCR subyacente (mediante propiedades indizadas como ordenadas) |
Filtrado de una gran cantidad de resultados debido al control de acceso | Aplique una propiedad indizada o una restricción de ruta adicional a la consulta para reflejar el control de acceso |
El uso de "paginación de desplazamiento" con un desplazamiento grande | Considere utilizar Paginación de conjunto de claves |
Iteración de números de resultados grandes o ilimitados | Considere utilizar Paginación de conjunto de claves |
Índice elegido incorrecto | Utilice Etiquetas en la consulta y la definición del índice para asegurarse de que se utiliza el índice esperado |