現在表示中:

AEM 6 では、Oak への移行のほか、クエリとインデックスの管理方法に対するいくつかの大きな変更が行われました。  Jackrabbit 2 では、すべてのコンテンツのインデックスがデフォルトで作成され、クエリを自由に実行できました。  Oak では、oak:index ノードにインデックスを手動で作成する必要があります。  クエリはインデックスがなくても実行できますが、データセットの規模が大きい場合は、クエリの実行速度が非常に遅くなります。

ここでは、インデックスを作成するべき場合とインデックスが不要な場合について、クエリが不要な場合にクエリの使用を回避するためのヒント、インデックスとクエリの機能をできる限り最適化するためのヒントについて説明します。

また、クエリとインデックスの作成に関する Oak のドキュメントもお読みください。  AEM 6 における新しい概念であるインデックスに加えて、以前の AEM インストールからコードを移行する際に考慮すべき Oak クエリの構文的な違いが存在します。

クエリを使用するタイミング

リポジトリと分類の設計

リポジトリの分類を設計する場合に考慮すべき要因がいくつか存在します。特に重要なのは、アクセス制御、ローカリゼーション、コンポーネントおよびページプロパティの継承です。

これらの課題に対処する分類を設計する場合は、インデックス作成の設計の「トラバーサビリティ」を考慮することも重要です。ここで、トラバーサビリティとは、パスに基づいてコンテンツに予想どおりにアクセスできる分類の機能のことです。これにより、さらに高性能のシステムが実現し、多数のクエリを実行する必要のあるシステムよりも保守が容易になります。

また、分類を設計する場合は、順序付けが重要かどうかを考慮してください。明示的な順序付けが不要で、多数の兄弟ノードが想定される場合は、sling:Folderoak:Unstructured などの順序なしのノードタイプを使用することをお勧めします。順序付けが必要な場合は、nt:unstructured および sling:OrderedFolder が適しています。

コンポーネントでのクエリ

クエリは AEM システムで実行される処理の中でも負荷が大きいものの 1 つなので、コンポーネントでは使用を避けることをお勧めします。ページがレンダリングされるたびに複数のクエリを実行すると、多くの場合、システムのパフォーマンスが低下します。コンポーネントのレンダリング時にクエリの実行を避けるための戦略は 2 つ(ノードのトラバース結果のプリフェッチ)あります。

ノードのトラバース

必要なデータの場所に関する予備知識の使用を許可するようにリポジトリが設計されている場合は、そのデータを見つけるためのクエリを実行することなく、必要なパスからデータを取得するコードをデプロイできます。

特定のカテゴリに含まれるコンテンツのレンダリングがその一例です。1 つの方法としては、カテゴリプロパティを使用してコンテンツを整理し、カテゴリ内の項目を表示するコンポーネントを指定するためのクエリをコンテンツに対して実行できます。

より優れた方法としては、分類内のこのコンテンツをカテゴリ別に構造化して、コンテンツを手動で取得できるようにします。

例えば、次のような分類にコンテンツが保存されているとします。

/content/myUnstructuredContent/parentCategory/childCategory/contentPiece

/content/myUnstructuredContent/parentCategory/childCategory ノードは簡単に取得でき、その子を解析してコンポーネントのレンダリングに使用できます。

また、小規模または同種の結果セットを扱う場合は、同じ結果セットを返すクエリを作成するのではなく、リポジトリを迅速にトラバースして必要なノードを収集できます。一般的な考慮事項として、可能な場合はクエリの使用を避けてください。

結果のプリフェッチ

コンテンツまたはコンポーネントに関する要件によっては、必要なデータを取得する方法としてノードのトラバーサルを使用できない場合があります。そのような場合は、コンポーネントがレンダリングされる前に必要なクエリを実行して、エンドユーザーに最適なパフォーマンスを提供しなければなりません。

コンポーネントに必要な結果の計算をコンポーネントのオーサリング時に行うことが可能であり、コンテンツ変更の予定がない場合は、作成者がダイアログ内の設定を適用する際にクエリを実行できます。

データまたはコンテンツが定期的に変更される場合は、スケジュールに従って、または基盤となるデータの更新のリスナーを使用してクエリを実行できます。その後で、リポジトリ内の共有の場所に結果を書き込むことができます。このデータを必要とするコンポーネントでは、単一のノードから値を抽出できます。実行時にクエリを実行する必要はありません。

クエリの最適化

インデックスを使用しないクエリを実行する場合は、ノードのトラバーサルに関する警告がログに記録されます。このクエリを頻繁に実行する場合は、インデックスを作成する必要があります。特定のクエリで使用するインデックスを決定するには、クエリの説明を実行ツールをお勧めします。  詳細を確認するために、関連する検索 API のデバッグログを有効にすることができます。

注意:

インデックス定義を変更したら、reindex プロパティを true に設定して、再インデックスにフラグを付ける必要があります。インデックスのサイズによっては、この処理が完了するまでにある程度の時間がかかる場合があります。

複雑なクエリの実行時には、そのクエリを複数の小さいクエリに分けて、事実がより明確になった後でコードを使用してデータを結合する場合があります。このような場合は、2 つの方法のパフォーマンスを比較して、適切なオプションを決定することをお勧めします。

AEM では、次の 3 つのいずれかの方法でクエリを作成できます。

すべてのクエリは実行前に SQL2 に変換されますが、クエリ変換のオーバーヘッドは最小限に抑えられるので、クエリ言語の選択時の最大の考慮事項は読みやすさと開発チームの快適度です。

注意:

QueryBuilder を使用する場合は結果数がデフォルトで決定されるので、以前のバージョンの Jackrabbit と比較すると、Oak の方が処理に時間がかかります。この処理速度の低下を補うには、guessTotal パラメーターを使用できます。

クエリの説明を実行ツール

どのクエリ言語でも同様ですが、クエリを最適化するための第一歩としては、クエリの実行方法について理解する必要があります。そのためには、操作ダッシュボードに含まれているクエリの説明を実行ツールを使用できます。  このツールでは、クエリを読み込んで、その説明を表示できます。クエリが原因でサイズの大きいリポジトリ、実行時間および使用されるインデックスに関する問題が発生した場合は、警告が表示されます。また、このツールは低速のクエリとよく使用されるクエリのリストを読み込んで、その説明を表示したり、最適化したりできます。

クエリのデバッグログ

使用するインデックスを Oak が選択する方法、およびクエリエンジンがクエリを実際に実行する方法に関する詳細を確認するには、次のパッケージに対してデバッグログ設定を追加できます。

  • org.apache.jackrabbit.oak.plugins.index
  • org.apache.jackrabbit.oak.query
  • com.day.cq.search

このロガーによって多数のアクティビティが出力され、ディスクがログファイルでいっぱいになってしまう可能性があるので、クエリのデバッグが完了したら、必ずロガーを削除してください。

その方法について詳しくは、ログに関するドキュメントを参照してください。

インデックス統計

Lucene では、インデックス作成されたコンテンツの詳細(各インデックスに含まれるドキュメントの数やサイズなど)を提供する JMX Bean を登録します。

JMX Bean を確認するには、JMX コンソール(http://server:port/system/console/jmx)にアクセスします。

JMX コンソールにログインしたら、「Lucene Index Statistics」を検索して特定します。他のインデックス統計は IndexStats MBean に含まれています。

クエリ統計については、「Oak Query Statistics」という名前の MBean を参照してください。

Luke などのツールでインデックスの詳細を確認する場合は、Oak コンソールを使用して、NodeStore からファイルシステムディレクトリにインデックスをダンプする必要があります。その手順については、Lucene のドキュメントを参照してください。

システム内のインデックスを JSON 形式で抽出することもできます。そのためには、次の URL にアクセスする必要があります。http://server:port/oak:index.tidy.-1.json

効率的なインデックス作成のヒント

インデックスを作成すべきかどうか

インデックスを作成または最適化する場合に生じる最初の疑問は、特定の状況においてインデックスが本当に必要かどうかということです。クエリを 1 回だけ実行する場合や、まれにしか実行しない場合、およびシステムのオフピーク時にバッチ処理で実行する場合は、インデックスを作成しない方がよいかもしれません。 

インデックスの作成後は、インデックス付きのデータを更新するたびに、インデックスも更新する必要があります。  これによりシステムのパフォーマンスに影響が及ぶので、インデックスは本当に必要な場合に限り作成してください。

また、インデックスが役立つのは、インデックス内のデータを保証するための一意性が確保されている場合のみです。ブック内のインデックスとインデックスがカバーするトピックについて検討してください。テキスト内の一連のトピックのインデックスを作成する場合、通常はエントリ数が何百件、何千件にもなりますが、ユーザーはページのサブセットにすばやくジャンプして、探している情報を簡単に見つけることができます。そのインデックスにエントリが 2 ~ 3 件しか含まれていない場合は、各エントリの参照先が数百ページにも及ぶので、インデックスはあまり役に立ちません。この同じ概念がデータベースインデックスにも該当します。つまり、一意の値が数個しかない場合は、インデックスがあまり役に立ちません。  とは言うものの、サイズが大きくなりすぎてインデックスが役に立たなくなる場合もあります。インデックス統計を確認するには、前述のインデックス統計を参照してください。

Lucene インデックスとプロパティインデックスのどちらを使用するか

Lucene インデックスは Oak 1.0.9 で導入されました。このインデックスは、AEM 6 の最初のリリース時に導入されたプロパティインデックスよりも強力な最適化を提供します。Lucene インデックスとプロパティインデックスのどちらを使用するかを決定するときには、次の点を考慮してください。

  • Lucene インデックスは、プロパティインデックスよりも多くの機能を提供します。例えば、プロパティインデックスは 1 つのプロパティのインデックスしか作成できませんが、Lucene インデックスには多くのプロパティを含めることができます。Lucene インデックスで使用可能なすべての機能について詳しくは、このドキュメントを参照してください。
  • Lucene インデックスは非同期です。これによりパフォーマンスが大幅に向上しますが、リポジトリへのデータの書き込み時とインデックスの更新時との間に遅延が生じる場合もあります。100%正確な結果がクエリから返されるようにすることが重要な場合は、プロパティインデックスが必要です。
  • Lucene インデックスは非同期なので、一意性制約を適用できません。  この制約が必要な場合は、プロパティインデックスを使用する必要があります。

通常は、プロパティインデックスをどうしても使用しなければならない場合を除き、Lucene インデックスを使用することをお勧めします。Lucene インデックスを使用することで、パフォーマンスと柔軟性の向上のメリットが得られます。

Solr インデックスの作成

AEM では、Solr インデックスの作成もデフォルトでサポートされています。これは主に全文検索をサポートするために活用されますが、任意のタイプの JCR クエリをサポートするために使用することもできます。検索を集中的に使用するデプロイメント(同時ユーザー数が多い検索型 Web サイトなど)で必要な数のクエリを処理するための CPU 容量が AEM インスタンスにない場合は、Solr を検討してください。また、プラットフォームのより高度な機能を活用するクローラーベースの手法では、Solr を実装できます。

開発環境では、AEM サーバーに組み込んで実行するように Solr インデックスを設定できます。または、Solr インデックスをリモートインスタンスにオフロードすると、実稼働環境とステージング環境における検索のスケーラビリティが向上します。検索のオフロードによってスケーラビリティは向上しますが、待ち時間が生じるので、必要でない限りこの方法はお勧めしません。Solr 統合の設定方法と Solr インデックスの作成方法について詳しくは、Oak クエリとインデックス作成に関するドキュメントを参照してください。

注意:

統合された Solr の検索手法では、Solr サーバーへのインデックス作成のオフロードが許可されます。Solr サーバーのより高度な機能がクローラーベースの手法で使用される場合は、追加の設定作業が必要になります。このようなタイプの実装の時間を短縮するためのオープンソースのコネクタが Headwire によって作成されています。

この手法の欠点として、デフォルトでは AEM クエリが ACL に従って、ユーザーがアクセス権を持っていない結果を非表示にしますが、検索を Solr サーバーに外部化するとこの機能がサポートされなくなります。このように検索を外部化する場合は、ユーザーには表示されないはずの結果が表示されないように十分な注意が必要です。

この手法が適しているのは、複数のソースの検索データを集計する必要がある場合です。例えば、1 つ目のサイトは AEM でホストされていて、2 つ目のサイトはサードパーティのプラットフォームでホストされているとします。この場合、両方のサイトのコンテンツをクロールして集計インデックスに保存するように Solr を設定できます。これにより、サイト間検索が可能になります。

設計に関する考慮事項

Lucene インデックスに関する Oak ドキュメントには、インデックス設計時のいくつかの考慮事項が記載されています。

  • 異なる複数のパス制限をクエリで使用する場合は、evaluatePathRestrictions を指定してください。これにより、指定されたパスにある結果のサブセットをクエリから返し、それらをクエリに基づいてフィルターできます。それ以外の場合は、リポジトリ内でクエリパラメーターに一致するすべての結果をクエリが検索し、パスに基づいてそれらをフィルタリングします。
  • クエリで並べ替えを使用する場合は、並べ替えるプロパティの明示的なプロパティ定義を用意し、その定義の orderedtrue に設定してください。これにより、インデックス内の結果が並べ替えられて、クエリの実行時に負担の大きい並べ替え処理を軽減できます。
  • 必要な項目だけをインデックスに格納してください。不要な機能やプロパティを追加すると、インデックスが増大してパフォーマンスが低下します。
  • プロパティインデックスでは、一意のプロパティ名を使用するとインデックスのサイズを軽減できますが、Lucene インデックスでは、nodeTypesmixins を使用して、一貫性のあるインデックスを作成する必要があります。特定の nodeType または mixin に対するクエリの実行は、nt:base に対するクエリの実行よりも効率的です。この方法を使用する場合は、対象となる nodeTypesindexRules を定義してください。
  • クエリが特定のパスでのみ実行される場合は、それらのパスにインデックスを作成してください。リポジトリのルートにインデックスを配置する必要はありません。
  • できるだけ多くのプロパティ制限を Lucene でネイティブに評価できるようにするには、インデックスを作成するすべてのプロパティに関連性がある場合に、1 つのインデックスを使用することをお勧めします。また、結合を実行する場合であっても、クエリで使用するインデックスは 1 つだけです。

CopyOnRead

NodeStore がリモートで保存される場合は、CopyOnRead オプションを有効にすることができます。このオプションを使用すると、読み込み時にリモートインデックスがローカルファイルシステムに書き込まれます。そのため、これらのリモートインデックスに対して頻繁に実行されるクエリのパフォーマンスが向上します。

このオプションは OSGi コンソールの LuceneIndexProvider サービスで設定可能であり、Oak 1.0.13 以降はデフォルトで有効になっています。

インデックスの削除

インデックスを削除する場合は、実際に削除する前に type プロパティを disabled に設定してインデックスを一時的に無効にし、アプリケーションが正しく機能するかどうかをテストすることを常にお勧めします。インデックスを無効にした場合、インデックスは更新されません。そのため、再度有効にした場合に正しいコンテンツが含まれておらず、再度インデックスを作成しなければならないことがあります。

TarMK インスタンスでプロパティインデックスを削除したら、コンパクト化を実行して、使用されていたディスク領域を再利用する必要があります。Lucene インデックスの場合は、実際のインデックスコンテンツが BlobStore に保存されているので、データストアのガベージコレクションが必要です。

MongoDB インスタンスでインデックスを削除する場合は、削除の負荷がインデックス内のノード数に比例します。サイズの大きいインデックスを削除すると問題が発生する可能性があるので、oak-mongo.js などのツールを使用してインデックスを無効にし、メンテナンス期間にのみインデックスを削除することをお勧めします。データの不整合が生じる可能性があるので、通常のノードコンテンツに対してはこの方法を採用しないでください。

注意:

oak-mongo.js について詳しくは、Oak ドキュメントのコマンドラインツールに関する節を参照してください。

本作品は Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License によってライセンス許可を受けています。  Twitter™ および Facebook の投稿には、Creative Commons の規約内容は適用されません。

法律上の注意   |   プライバシーポリシー