No AEM as a Cloud Service, todos os aspectos operacionais relativos à indexação são automatizados. Isso permite que os desenvolvedores se concentrem na criação de consultas eficientes e suas definições de índice correspondentes.
As consultas são uma maneira de acessar conteúdo, mas não são a única possibilidade. Em muitas situações, o conteúdo do repositório pode ser acessado com mais eficiência por outros meios. Você deve considerar se as consultas são a melhor e mais eficiente maneira de acessar o conteúdo no seu caso de uso.
Ao projetar a taxonomia de um repositório, vários fatores precisam ser considerados. Entre eles, controles de acesso, localização, herança de propriedade de componente e página e muito mais.
Ao projetar uma taxonomia que atenda a essas questões, também é importante considerar a flexibilidade do design de indexação. Nesse contexto, a “flexibilidade” é a capacidade de uma taxonomia permitir que o conteúdo seja acessado de forma previsível com base em seu caminho. Isso torna o sistema mais eficiente e fácil de manter do que um que requer a execução de várias consultas.
Além disso, ao projetar uma taxonomia, é importante considerar se a ordenação é importante. Nos casos em que a ordenação explícita não é obrigatória e um grande número de nós semelhantes é esperado, é preferível usar um tipo de nó não ordenado, como sling:Folder
ou oak:Unstructured
. Nos casos em que a ordenação é obrigatória, nt:unstructured
e sling:OrderedFolder
seriam mais adequados.
Como as consultas podem ser uma das operações mais exigentes realizadas em um sistema AEM, é recomendável evitá-las em seus componentes. A execução de várias consultas cada vez que uma página é renderizada pode prejudicar o desempenho do sistema. Há duas estratégias que podem ser usadas para evitar a execução de consultas ao renderizar componentes: nós de passagem e resultados de busca prévia.
Se o repositório for projetado de uma forma que permita o conhecimento prévio da localização dos dados necessários, o código que recupera esses dados dos caminhos necessários poderá ser implantado sem a necessidade de executar consultas para encontrá-los.
Um exemplo disso seria a renderização de um conteúdo que se encaixe em uma determinada categoria. Uma abordagem seria organizar o conteúdo com uma propriedade de categoria que possa ser consultada para preencher um componente que mostre itens em uma categoria.
No entanto, uma melhor abordagem seria estruturar esse conteúdo em uma taxonomia por categoria para que ele possa ser recuperado manualmente.
Por exemplo, se o conteúdo for armazenado em uma taxonomia semelhante a:
/content/myUnstructuredContent/parentCategory/childCategory/contentPiece
o nó /content/myUnstructuredContent/parentCategory/childCategory
pode simplesmente ser recuperado e seus secundários podem ser analisados e usados para renderizar o componente.
Além disso, ao lidar com um conjunto de resultados pequeno ou homogêneo, pode ser mais rápido percorrer o repositório e coletar os nós necessários, em vez de criar uma consulta para retornar o mesmo conjunto de resultados. Como consideração geral, as consultas devem ser evitadas sempre que possível.
Às vezes, o conteúdo ou os requisitos do componente não permitem o uso de nós de passagem como um método de recuperação dos dados necessários. Nesses casos, as consultas obrigatórias precisam ser executadas antes que o componente seja renderizado para garantir um desempenho ideal.
Se os resultados obrigatórios para o componente puderem ser calculados no momento da criação e não houver expectativa de que o conteúdo seja alterado, a consulta poderá ser executada após uma alteração ter sido feita.
Se os dados ou o conteúdo forem alterados regularmente, a consulta poderá ser executada de acordo com uma programação ou por meio de um ouvinte para obter atualizações sobre os dados subjacentes. Em seguida, os resultados podem ser gravados em um local compartilhado no repositório. Qualquer componente que precise desses dados pode extrair os valores desse único nó, sem precisar executar uma consulta em tempo de execução.
Uma estratégia semelhante pode ser usada para manter o resultado em uma memória cache, que é preenchida na inicialização e atualizada sempre que as alterações são feitas (usando um JCR ObservationListener
ou um Sling ResourceChangeListener
).
A documentação do Oak fornece uma visão geral de alto nível de como as consultas são executadas. Isso forma a base de todas as atividades de otimização descritas neste documento.
O AEM as a Cloud Service fornece a Ferramenta de desempenho da consulta, que foi projetado para suportar a implementação de consultas eficientes.
A Ferramenta de desempenho de consulta pode ser acessada por meio do Console do desenvolvedor no Cloud Manager. A Ferramenta de desempenho de consulta do AEM as a Cloud Service fornece mais detalhes sobre a execução da consulta do que a versão AEM 6.x.
Este gráfico ilustra o fluxo geral de uso da Ferramenta de desempenho de consulta na otimização de consultas.
Cada consulta deve usar um índice para fornecer desempenho ideal. Na maioria dos casos, os índices prontos para uso existentes devem ser suficientes para lidar com as consultas.
Às vezes, as propriedades personalizadas precisam ser adicionadas a um índice existente, para que restrições adicionais possam ser consultadas usando o índice. Consulte o documento Pesquisa e indexação de conteúdo para obter mais detalhes. A variável Folha de características de consulta JCR seção deste documento descreve como deve ser uma definição de propriedade em um índice para suportar um tipo de consulta específico.
A restrição primária em qualquer consulta deve ser uma correspondência de propriedade, pois este é o tipo mais eficiente. Adicionar mais restrições de propriedade limita ainda mais o resultado.
O mecanismo de consulta considera apenas um único índice. Isso significa que um índice existente pode e deve ser personalizado adicionando mais propriedades de índice personalizadas a ele.
A variável Folha de características de consulta JCR A seção deste documento lista as restrições disponíveis e também descreve como deve ser uma definição de índice para que seja escolhida. Use a Ferramenta de desempenho da consulta para testar a consulta e garantir que o índice correto esteja sendo usado e que o mecanismo de consulta não precise avaliar restrições fora do índice.
Se uma ordem específica do resultado for solicitada, há duas maneiras de o mecanismo de consulta alcançar isso:
ordered=true
na definição do índice.ordered=true
.O tamanho recuperado do resultado da consulta é um fator importante no desempenho da consulta. Como o resultado é recebido lentamente, há uma diferença entre obter apenas os primeiros 20 resultados e obter 10.000 resultados, tanto em tempo de execução quanto em uso de memória.
Isso também significa que o tamanho do conjunto de resultados só poderá ser determinado corretamente se todos os resultados forem obtidos. Por esse motivo, o conjunto de resultados obtido deve ser sempre limitado, seja aumentando a consulta (consulte a seção Folha de características de consulta JCR para obter detalhes) ou limitando as leituras dos resultados.
Esse limite também impede que o mecanismo de consulta atinja o limite de passagem de 100.000 nós, o que resulta em uma interrupção forçada da consulta.
Consulte a seção Consultas com conjuntos de resultados grandes deste documento se um conjunto de resultados potencialmente grande tiver de ser processado por completo.
A Ferramenta de desempenho de consulta (localizada em /libs/granite/operations/content/diagnosistools/queryPerformance.html
e disponível por meio da Console do desenvolvedor no Cloud Manager) fornece -
As tabelas "Consultas lentas" e "Consultas populares" incluem -
Essas tabelas ajudam a identificar consultas que não estão totalmente indexadas (consulte Usar um índice ou estão lendo muitos nós (consulte também Percurso do repositório e Travessia de índice). Esses queries serão destacados - com as áreas de preocupação apropriadas marcadas em vermelho.
A variável Reset Statistics
é fornecida a opção para remover todas as estatísticas existentes coletadas nas tabelas. Isso permite a execução de uma consulta específica (por meio do próprio aplicativo ou da ferramenta Explain Query ) e a análise das estatísticas de execução.
A Ferramenta Explicar consulta permite que os desenvolvedores entendam o Plano de execução da consulta (consulte Lendo o Plano de Execução da Consulta), incluindo detalhes de quaisquer índices usados ao executar a query. Isso pode ser usado para entender com que eficiência uma consulta é indexada para prever ou analisar retrospectivamente seu desempenho.
Para explicar uma consulta, faça o seguinte:
Language
lista suspensa.Query
campo.Include Execution Time
- executar a consulta, mas não tentar ler os resultados.Read first page of results
- executar a consulta e ler a primeira "página" de 20 resultados (replicação das práticas recomendadas para executar consultas).Include Node Count
- executar a consulta e ler todo o conjunto de resultados (geralmente isso não é recomendável - consulte Travessia de índice).Depois de selecionar Explain
, o usuário verá um pop-up descrevendo o resultado da explicação da consulta (e a execução, se selecionada).
Esse pop-up inclui detalhes de -
Include Execution Time
foi marcada) e a contagem de resultados lidos (se Read first page of results
ou Include Node Count
foram marcadas).Read first page of results
foi marcada)O Plano de Execução de Consulta contém tudo o que é necessário para prever (ou explicar) o desempenho de uma determinada consulta. Entenda com que eficiência a consulta será executada comparando as restrições e a ordenação na consulta JCR original (ou Construtor de consultas) com a consulta executada no índice subjacente (Lucene, Elastic ou Property).
Considere a seguinte consulta -
/jcr:root/content/dam//element(*, dam:Asset) [jcr:content/metadata/dc:title = "My Title"] order by jcr:created
…que contém -
dam:Asset
)/content/dam
)jcr:content/metadata/dc:title = "My Title"
)jcr:created
propriedadeA explicação desta consulta resulta no seguinte plano -
[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])) */
Neste plano, a seção que descreve a consulta executada no índice subjacente é -
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 seção do plano indica que:
/oak:index/damAssetLucene-9
serão usadas, portanto, as informações restantes estarão na Sintaxe de consulta Lucene.damAssetLucene-9
indexa somente nós do tipo dam:Asset.+:ancestors:/content/dam
aparece na query Lucene.+jcr:content/metadata/dc:title:My Title
aparece na query Lucene.ordering:[{ propertyName : jcr:created, propertyType : UNDEFINED, order : ASCENDING }]
aparece na query Lucene.Essa consulta provavelmente terá um bom desempenho, já que os resultados retornados da consulta de índice não serão filtrados ainda mais no mecanismo de consulta (além da filtragem de Controle de acesso). No entanto, esse query ainda poderá ser executado lentamente se as práticas recomendadas não forem seguidas - consulte Travessia de índice abaixo.
Considerando uma consulta diferente -
/jcr:root/content/dam//element(*, dam:Asset) [jcr:content/metadata/myProperty = "My Property Value"] order by jcr:created
…que contém -
dam:Asset
)/content/dam
)jcr:content/metadata/myProperty = "My Property Value"
)jcr:created
propriedade**A explicação desta consulta resulta no seguinte plano -
[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])) */
Neste plano, a seção que descreve a consulta executada no índice subjacente é -
lucene:damAssetLucene-9(/oak:index/damAssetLucene-9) :ancestors:/content/dam ordering:[{ propertyName : jcr:created, propertyType : UNDEFINED, order : ASCENDING }]
Esta seção do plano indica que:
damAssetLucene-9
indexa somente nós do tipo dam:Asset.+:ancestors:/content/dam
aparece na query Lucene.jcr:content/metadata/myProperty = "My Property Value"
não é executado no índice, mas será aplicado como filtragem do Mecanismo de consulta nos resultados da consulta Lucene subjacente.
+jcr:content/metadata/myProperty:My Property Value
não aparece na consulta Lucene, pois essa propriedade não está indexada na variável damAssetLucene-9
índice usado para esta consulta.Este plano de execução de consulta resultará em cada ativo abaixo de /content/dam
sendo lidos a partir do índice e filtrados ainda mais pelo mecanismo de consulta (que incluirá somente aqueles que correspondem à restrição de propriedade não indexada no conjunto de resultados).
Mesmo que apenas uma pequena porcentagem de ativos corresponda à restrição jcr:content/metadata/myProperty = "My Property Value"
, a consulta deve ler um grande número de nós para (tentar) preencher a “página” de resultados solicitada. Isso pode resultar em uma consulta com baixo desempenho, que será mostrada como tendo um baixo Read Optimization
na ferramenta Desempenho da consulta) e pode levar a mensagens de AVISO indicando que um grande número de nós está sendo percorrido (consulte Travessia de índice).
Para otimizar o desempenho desta segunda query, crie uma versão personalizada do damAssetLucene-9
índice (damAssetLucene-9-custom-1
) e adicione a seguinte definição de propriedade -
"myProperty": {
"jcr:primaryType": "nt:unstructured",
"propertyIndex": true,
"name": "jcr:content/metadata/myProperty"
}
Para auxiliar na criação de consultas JCR e definições de índice eficientes, a Folha de características de consulta JCR está disponível para download e uso como referência durante o desenvolvimento.
Ela contém exemplos de consulta para o QueryBuilder, XPath e SQL-2, e abrange vários cenários que se comportam de maneira diferente em termos de desempenho de consulta. Ela também fornece recomendações sobre como criar ou personalizar índices do Oak. O conteúdo desta Folha de características se aplica ao AEM as a Cloud Service e ao AEM 6.5.
Abaixo estão algumas práticas recomendadas a serem consideradas ao definir ou estender índices.
dam:Asset
ou cq:Page
) prefira a extensão de índices OOTB à adição de novos índices.
dam:Asset
nodetype é altamente desencorajado (consulte esta observação).selectionPolicy = tag
para garantir que o índice seja usado apenas para as consultas desejadas.queryPaths
e includedPaths
ambos são fornecidos (normalmente com os mesmos valores).excludedPaths
para excluir caminhos que não conterão resultados úteis.analyzed
propriedades somente quando necessário, por exemplo, quando é necessário usar uma restrição de consulta de texto completo somente para essa propriedade.async = [ async, nrt ]
, compatVersion = 2
e evaluatePathRestrictions = true
.nodeScopeIndex = true
se você precisar de um índice de texto completo do nodescope.Para obter mais informações, consulte Documentação do índice Oak Lucene.
As verificações de pipeline do Automated Cloud Manager aplicarão algumas das práticas recomendadas descritas acima.
Embora seja recomendável evitar consultas com conjuntos de resultados grandes, há casos válidos em que eles precisam ser processados. Muitas vezes, o tamanho do resultado não é conhecido antecipadamente. Portanto, algumas precauções devem ser tomadas para tornar o processamento confiável.
As consultas que percorrem o repositório não usam um índice e são registradas com uma mensagem semelhante à seguinte.
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
Com este trecho de log, você pode determinar:
//*
com.adobe.granite.queries.impl.explain.query.ExplainQueryServlet::getHeuristics
para ajudar a identificar o criador da consulta.Com essas informações, é possível otimizar a consulta usando os métodos descritos na seção Otimização de consultas deste documento.
As consultas que usam um índice, mas ainda leem um grande número de nós, são registradas com uma mensagem semelhante à seguinte (observe o termo Index-Traversed
em vez 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//*)
Isso pode ocorrer por vários motivos:
Causa | Mitigação |
---|---|
A Comissão de p.guessTotal (ou o uso de um guessTotal muito grande) fazendo com que o QueryBuilder iterasse um grande número de resultados de contagem |
Fornecer p.guessTotal com um valor apropriado |
O uso de um limite grande ou não vinculado no Construtor de consultas (ou seja, p.limit=-1 ) |
Use um valor apropriado para p.limit (idealmente 1000 ou inferior) |
O uso de um predicado de filtragem no Construtor de consultas, que está filtrando um grande número de resultados da consulta JCR subjacente | Substituir os predicados de filtragem por restrições que podem ser aplicadas na consulta JCR subjacente |
O uso de uma classificação baseada em Comparador no QueryBuilder | Substituir pela ordenação baseada em propriedades na consulta JCR subjacente (usando propriedades indexadas conforme ordenadas) |
Filtragem de um grande número de resultados devido ao Controle de acesso | Aplicar propriedade indexada adicional ou restrição de caminho à consulta para espelhar o Controle de acesso |
O uso de 'paginação de deslocamento' com um deslocamento grande | Considere usar Paginação do conjunto de chaves |
Iteração de um número grande ou ilimitado de resultados | Considere usar Paginação do conjunto de chaves |
Índice incorreto escolhido | Use Tags na definição de consulta e índice para garantir que o índice esperado seja usado |