Query Builder を使用すると、AEM のコンテンツリポジトリーへのクエリを簡単に実行できます。この機能は、Java API と REST API を通じて公開されます。この文書ではこれらの API について説明します。
サーバーサイド Query Builder(QueryBuilder
)はクエリの記述を受け入れ、XPath クエリを作成して実行します。必要に応じて任意に、結果セットのフィルタリングや、ファセットの抽出も実行できます。
クエリの記述は、単に述語(Predicate
)のセットです。例としては、XPath の jcr:contains()
関数に対応するフルテキスト述語などがあります。
各述語タイプに、1 つのエバリュエーターコンポーネント(PredicateEvaluator
)があります。これらのコンポーネントは、XPath、フィルタリングおよびファセットの抽出に対してその特定の述語を処理する方法を理解しています。OSGi コンポーネントランタイムを通じてプラグインされるカスタムエバリュエーターは、簡単に作成できます。
REST API は、JSON で送信される応答と HTTP を通じて、まったく同じ機能にアクセスできます。
QueryBuilder API は、JCR API を使用して構築されます。 また、OSGi バンドル内から JCR API を使用して、AEM JCR をクエリすることもできます。詳しくは、 JCR API を使用したAdobe Experience Managerデータのクエリ.
AEM Gems は、Adobe Experience Manager を技術的に深く掘り下げるための、アドビのエキスパートによる各種セッションです。
Query Builder 専用のセッションを確認し、ツールの概要と使用方法を確認できます。
以下のサンプルは、Java プロパティのスタイル表記法で示されています。これらのサンプルを Java API で使用するには、この後の API サンプルのように Java HashMap
を使用します。
QueryBuilder
JSON サーブレットの場合、各例には AEM インストールへのリンクの例が含まれています(デフォルトの場所:http://<host>:<port>
)。これらのリンクを使用する前に、AEM インスタンスにログインする必要があります。
デフォルトでは、この Query Builder JSON サーブレットは最大 10 件の結果を表示します。
次のパラメーターを追加すると、サーブレットですべてのクエリ結果を表示できます。
p.limit=-1
返された JSON データをブラウザーで表示するのに、Firefox 用 JSONView などのプラグインを使用できます。
以下のクエリは 10 件の結果を返します(正確には最大 10 件)が、通知されるのは実際に表示可能なヒット数です。
http://<host>:<port>/bin/querybuilder.json?path=/content&1_property=sling:resourceType&1_property.value=wknd/components/structure/page&1_property.operation=like&orderby=path
path=/content
1_property=sling:resourceType
1_property.value=wknd/components/structure/page
1_property.operation=like
orderby=path
同じクエリで、パラメーター p.limit=-1
を使用すると、すべての結果が返されます(インスタンスによっては非常に多くなることがあります)。
http://<host>:<port>/bin/querybuilder.json?path=/content&1_property=sling:resourceType&1_property.value=wknd/components/structure/page&1_property.operation=like&orderby=path&p.limit=-1
path=/content
1_property=sling:resourceType
1_property.value=wknd/components/structure/page
1_property.operation=like
p.limit=-1
orderby=path
p.guessTotal
パラメーターの目的は、実用最小限の p.offset
値と p.limit
値を組み合わせることによって、表示できる適切な結果数を返すことです。このパラメーターを使用するメリットは、結果セットが大きい場合にパフォーマンスが向上することです。これにより、総合計の計算(例:result.getSize()
の呼び出し)と結果セット全体の読み込みが回避され、OAK エンジンおよびインデックスに至るまですべてが最適化されます。結果が 10 万件ある場合、実行時間とメモリ使用量の両方で大きな変化が見られる可能性があります。
このパラメーターのデメリットは、ユーザーには正確な合計が表示されないことです。ただし、p.guessTotal=1000
のように最小値を設定することで、1000 件までは必ず読み込まれれるにできます。その結果、それより小さな結果セットについては正確な合計を取得できますが、それを超えた場合は「それ以上」ということしかわかりません。
以下のクエリに p.guessTotal=true
を追加して、どのように機能するかを見てみましょう。
http://<host>:<port>/bin/querybuilder.json?path=/content&1_property=sling:resourceType&1_property.value=wknd/components/structure/page&1_property.operation=like&p.guessTotal=true&orderby=path
path=/content
1_property=sling:resourceType
1_property.value=wknd/components/structure/page
1_property.operation=like
p.guessTotal=true
orderby=path
このクエリは、p.limit
のデフォルトである 10
件の結果をオフセット 0
で返します。
"success": true,
"results": 10,
"total": 10,
"more": true,
"offset": 0,
数値を使用してカスタムの最大結果数までカウントアップすることもできます。上述と同じクエリを使用して、p.guessTotal
の値を 50
に変更してみます。
http://<host>:<port>/bin/querybuilder.json?path=/content&1_property=sling:resourceType&1_property.value=wknd/components/structure/page&1_property.operation=like&p.guessTotal=50&orderby=path
このクエリは、同じデフォルトの制限である 10 件の結果をオフセット 0 で返しますが、表示されるのは最大 50 件までです。
"success": true,
"results": 10,
"total": 50,
"more": true,
"offset": 0,
デフォルトでは、Query Builder にもヒット数が表示されます。 結果のサイズによっては、正確なカウントを決定する際に、すべての結果にアクセス制御を確認する必要があるので、時間がかかる場合があります。 合計は、ほとんどの場合、エンドユーザー UI のページネーションの実装に使用されます。 正確な数の決定には時間がかかる場合があるので、guessTotal 機能を利用してページネーションを実装することをお勧めします。
例えば、UI は次の方法に適応できます。
100 以下の合計ヒット数の正確な数(SearchResult.getTotalMatches() または querybuilder.json
応答の合計)を取得して表示します。
guessTotal
を 100 に設定して、Query Builder への呼び出しを作成します。
応答は、以下のような結果になります。
total=43
、more=false
- 合計ヒット数が 43 であることを意味します。UI には先頭ページの一部として 10 件の結果が表示され、続く 3 ページのページネーションが提供されます。この実装を使用して、「43 件の結果が見つかりました」のような説明テキストを表示することもできます。total=100
、more=true
- 合計ヒット数が 100 を超え、正確な数が不明であることを意味します。UI は、最初のページの一部として最大 10 個を表示し、次の 10 ページのページネーションを提供できます。 また、これを使用して、 "100 件を超える結果が見つかりました". ユーザーが次のページに移動すると、Query Builder への呼び出しによって guessTotal
の制限と、offset
パラメーターおよび limit
パラメーターの制限が増やされます。UI が無限スクロールを使用する必要がある場合は、Query Builder によって正確なヒット数が決定されないように、guessTotal
も使用する必要があります。
http://<host>:<port>/bin/querybuilder.json?type=nt:file&nodename=*.jar&orderby=@jcr:content/jcr:lastModified&orderby.sort=desc
type=nt:file
nodename=*.jar
orderby=@jcr:content/jcr:lastModified
orderby.sort=desc
http://<host>:<port>/bin/querybuilder.json?type=cq:Page&orderby=@jcr:content/cq:lastModified
type=cq:Page
orderby=@jcr:content/cq:lastModified
http://<host>:<port>/bin/querybuilder.json?type=cq:Page&orderby=@jcr:content/cq:lastModified&orderby.sort=desc
type=cq:Page
orderby=@jcr:content/cq:lastModified
orderby.sort=desc
http://<host>:<port>/bin/querybuilder.json?fulltext=Management&orderby=@jcr:score&orderby.sort=desc
fulltext=Management
orderby=@jcr:score
orderby.sort=desc
http://<host>:<port>/bin/querybuilder.json?type=cq:Page&tagid=wknd:activity/cycling&tagid.property=jcr:content/cq:tags
type=cq:Page
tagid=wknd:activity/cycling
tagid.property=jcr:content/cq:tags
明確なタグ ID がわかっている場合は、例にあるように tagid
述語を使用します。
タグタイトルのパス(スペースなし)には、tag
述語を使用します。
前の例ではページ(cq:Page
ノード)を検索しているので、tagid.property
述語にはそのノードからの相対パス(jcr:content/cq:tags
)を使用する必要があります。デフォルトでは、tagid.property
は、単に cq:tags
となります。
http://<host>:<port>/bin/querybuilder.json?fulltext=Experience&group.1_path=/content/wknd/us/en/magazine&group.2_path=/content/wknd/us/en/adventures&group.p.or=true
fulltext=Experience
group.p.or=true
group.1_path=/content/wknd/us/en/magazine
group.2_path=/content/wknd/us/en/adventures
このクエリでは、クエリ内のサブ式を区切る役目を果たす「グループ」(group
)を使用しているので、使用しています(標準的な表記法での括弧と同様)。例えば、前の例は、次のように、よりわかりやすいスタイルで表現することができます。
"Experience" and ("/content/wknd/us/en/magazine" or "/content/wknd/us/en/adventures")
例にあるグループの内部では、path
述語が複数回使用されています。この述語の 2 つのインスタンスの区別と順序付け(一部の述語では順序付けが必要)を行う場合は、述語にプレフィックス N_
を付けます。N
は順序を表すインデックスです。前の例では、こうして得られた述語は、1_path
および 2_path
です。
p.or
内の p
は特殊な区切り文字で、後に続くもの(このケースでは or
)がグループのパラメーターであることを示します。これは、グループのサブ述語(1_path
など)とは対照的です。
p.or
が指定されない場合、すべての述語は AND で連結されます。つまり、各結果がすべての述語を満たすことが必要になります。
異なる述語に対してであっても、単一のクエリ内で同じ数値のプレフィックスを使用することはできません。
cq:template
プロパティを使用して、特定のテンプレートのすべてのページを検索できます。
http://<host>:<port>/bin/querybuilder.json?property=cq%3atemplate&property.value=%2fconf%2fwknd%2fsettings%2fwcm%2ftemplates%2fadventure-page-template&type=cq%3aPageContent
type=cq:PageContent
property=cq:template
property.value=/conf/wknd/settings/wcm/templates/adventure-page-template
これには、ページ自身ではなく、ページの jcr:content
ノードが返されるという欠点があります。この問題を解決するには、相対パスで検索します。
http://<host>:<port>/bin/querybuilder.json?property=jcr%3acontent%2fcq%3atemplate&property.value=%2fconf%2fwknd%2fsettings%2fwcm%2ftemplates%2fadventure-page-template&type=cq%3aPage
type=cq:Page
property=jcr:content/cq:template
property.value=/conf/wknd/settings/wcm/templates/adventure-page-template
property 述語を複数回使用する場合、ここでも、数字のプレフィックスを付加する必要があります。
http://<host>:<port>/bin/querybuilder.json?1_property=jcr%3acontent%2fcq%3atemplate&1_property.value=%2fconf%2fwknd%2fsettings%2fwcm%2ftemplates%2fadventure-page-template&2_property=jcr%3acontent%2fjcr%3atitle&2_property.value=Cycling%20Tuscany&type=cq%3aPage
type=cq:Page
1_property=jcr:content/cq:template
1_property.value=/conf/wknd/settings/wcm/templates/adventure-page-template
2_property=jcr:content/jcr:title
2_property.value=Cycling Tuscany
1 つのプロパティに対して複数の値を検索する場合("A" or "B" or "C"
)に、グループが大きくならないようにするには、property
述語に複数の値を指定します。
http://<host>:<port>/bin/querybuilder.json?property=jcr%3atitle&property.1_value=Cycling%20Tuscany&property.2_value=Ski%20Touring&property.3_value=Whistler%20Mountain%20Biking
property=jcr:title
property.1_value=Cycling Tuscany
property.2_value=Ski Touring
property.3_value=Whistler Mountain Biking
複数値を持つプロパティの場合、複数の値が一致することを必須にできます("A" and "B" and "C"
)。
http://<host>:<port>/bin/querybuilder.json?property=jcr%3atitle&property.and=true&property.1_value=Cycling%20Tuscany&property.2_value=Ski%20Touring&property.3_value=Whistler%20Mountain%20Biking
property=jcr:title
property.and=true
property.1_value=Cycling Tuscany
property.2_value=Ski Touring
property.3_value=Whistler Mountain Biking
デフォルトでは、QueryBuilder JSON サーブレットは検索結果内の各ノードに関するデフォルトのプロパティのセット(path、name、title など)を返します。返されるプロパティを制御するには、次のいずれかの操作を実行します。
以下のように
p.hits=full
を指定すると、各ノードのすべてのプロパティが含まれるようになります。
http://<host>:<port>/bin/querybuilder.json?p.hits=full&property=jcr%3atitle&property.value=Cycling%20Tuscany
property=jcr:title
property.value=Cycling Tuscany
p.hits=full
以下のように
p.hits=selective
を使用して、取得するプロパティを
p.properties
で指定し、スペースで区切ります。
http://<host>:<port>/bin/querybuilder.json?p.hits=selective&p.properties=sling%3aresourceType%20jcr%3aprimaryType&property=jcr%3atitle&property.value=Cycling%20Tuscany
property=jcr:title
property.value=Cycling Tuscany
p.hits=selective
p.properties=sling:resourceType jcr:primaryType
他に実行可能な方法として、Query Builder の応答に子ノードを含めることができます。これを行うには、
p.nodedepth=n
を指定します。n
は、クエリが返すレベルの数です。子ノードが返されるようにするには、プロパティセレクターでそのように指定する必要があるので、注意してください。
p.hits=full
例:
http://<host>:<port>/bin/querybuilder.json?p.hits=full&p.nodedepth=5&property=jcr%3atitle&property.value=Cycling%20Tuscany
property=jcr:title
property.value=Cycling Tuscany
p.hits=full
p.nodedepth=5
述語の詳細については、Query Builder の述語リファレンスのページを参照してください。
PredicateEvaluator
クラスの Javadoc も参照してください。これらのクラスの Javadoc ドキュメントには、使用できるプロパティのリストが含まれています。
クラス名のプレフィックス(SimilarityPredicateEvaluator
の similar
など)は、クラスのプリンシパルプロパティです。このプロパティは、クエリ内で使用する述語の名前(小文字で使用)でもあります。
このようなプリンシパルプロパティの場合は、クエリを短縮して、完全修飾バリアント similar=/content/en
の代わりに similar.similar=/content/en
を使用できます。完全修飾フォームは、クラスのプリンシパル以外のすべてのプロパティに使用する必要があります。
String fulltextSearchTerm = "WKND";
// create query description as hash map (simplest way, same as form post)
Map<String, String> map = new HashMap<String, String>();
// create query description as hash map (simplest way, same as form post)
map.put("path", "/content");
map.put("type", "cq:Page");
map.put("group.p.or", "true"); // combine this group with OR
map.put("group.1_fulltext", fulltextSearchTerm);
map.put("group.1_fulltext.relPath", "jcr:content");
map.put("group.2_fulltext", fulltextSearchTerm);
map.put("group.2_fulltext.relPath", "jcr:content/@cq:tags");
// can be done in map or with Query methods
map.put("p.offset", "0"); // same as query.setStart(0) below
map.put("p.limit", "20"); // same as query.setHitsPerPage(20) below
Query query = builder.createQuery(PredicateGroup.create(map), session);
query.setStart(0);
query.setHitsPerPage(20);
SearchResult result = query.getResult();
// paging metadata
int hitsPerPage = result.getHits().size(); // 20 (set above) or lower
long totalMatches = result.getTotalMatches();
long offset = result.getStartIndex();
long numberOfPages = totalMatches / 20;
//Place the results in XML to return to client
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.newDocument();
//Start building the XML to pass back to the AEM client
Element root = doc.createElement( "results" );
doc.appendChild( root );
// iterating over the results
for (Hit hit : result.getHits()) {
String path = hit.getPath();
//Create a result element
Element resultel = doc.createElement( "result" );
root.appendChild( resultel );
Element pathel = doc.createElement( "path" );
pathel.appendChild( doc.createTextNode(path ) );
resultel.appendChild( pathel );
}
同じクエリが、Query Builder(JSON)サーブレットを使用して HTTP を介して実行されます。
http://<host>:<port>/bin/querybuilder.json?path=/content&type=cq:Page&group.p.or=true&group.1_fulltext=WKND&group.1_fulltext.relPath=jcr:content&group.2_fulltext=WKND&group.2_fulltext.relPath=jcr:content/@cq:tags&p.offset=0&p.limit=20
クエリはリポジトリーに保存して後で使用することができます。QueryBuilder
には次のシグネチャを持つ storeQuery
メソッドがあります。
void storeQuery(Query query, String path, boolean createFile, Session session) throws RepositoryException, IOException;
QueryBuilder#storeQuery
メソッドを使用すると、指定した Query
が、createFile
引数の値に応じてファイルまたはプロパティとしてリポジトリーに保存されます。次の例に、Query
をファイルとしてパス /mypath/getfiles
に保存する方法を示します。
builder.storeQuery(query, "/mypath/getfiles", true, session);
以前に保存したクエリはすべて、QueryBuilder#loadQuery
メソッドを使用してリポジトリーから読み込むことができます。
Query loadQuery(String path, Session session) throws RepositoryException, IOException
例えば、パス /mypath/getfiles
に保存された Query
は、次のコードによって読み込むことができます。
Query loadedQuery = builder.loadQuery("/mypath/getfiles", session);
Query Builder のクエリを試してみたり、デバッグしたりする場合は、次の URL にアクセスして、Query Builder Debugger コンソールを使用できます。
http://<host>:<port>/libs/cq/search/content/querydebug.html
または、次の URL にアクセスして、Query Builder JSON サーブレットを使用できます。
http://<host>:<port>/bin/querybuilder.json?path=/tmp
path=/tmp
は単なる例です。
説明 すべて ターゲットインデックスセットに対する開発サイクル中のクエリ。
https://<host>:<port>/system/console/slinglog
に移動します。DEBUG に、com.day.cq.search.impl.builder.QueryImpl
の新しいロガーを作成します。com.day.cq.search.impl.builder.QueryImpl XPath query: /jcr:root/content//element(*, cq:Page)[(jcr:contains(jcr:content, "WKND") or jcr:contains(jcr:content/@cq:tags, "WKND"))]
AEM Query Builder Debugger を使用して、説明可能な XPath クエリを生成します。
Query Builder 以外のクエリ(XPath、 JCR-SQL2)は、クエリの説明を実行に直接指定できます。
ロガーの設定は、ドキュメント「ロギング」に記述されています。
前の「テストおよびデバッグ」節に記述されたクエリを実行したときの Query Builder 実装のログ出力(情報レベル)。
com.day.cq.search.impl.builder.QueryImpl executing query (predicate tree):
null=group: limit=20, offset=0[
{group=group: or=true[
{1_fulltext=fulltext: fulltext=WKND, relPath=jcr:content}
{2_fulltext=fulltext: fulltext=WKND, relPath=jcr:content/@cq:tags}
]}
{path=path: path=/content}
{type=type: type=cq:Page}
]
com.day.cq.search.impl.builder.QueryImpl XPath query: /jcr:root/content//element(*, cq:Page)[(jcr:contains(jcr:content, "WKND") or jcr:contains(jcr:content/@cq:tags, "WKND"))]
com.day.cq.search.impl.builder.QueryImpl no filtering predicates
com.day.cq.search.impl.builder.QueryImpl query execution took 69 ms
フィルターを行う述語エバリュエーターや、コンパレーターでカスタム順序を使用する述語エバリュエーターを使用するクエリがある場合は、クエリ内にそのことも記述されます。
com.day.cq.search.impl.builder.QueryImpl executing query (predicate tree):
null=group: [
{nodename=nodename: nodename=*.jar}
{orderby=orderby: orderby=@jcr:content/jcr:lastModified}
{type=type: type=nt:file}
]
com.day.cq.search.impl.builder.QueryImpl custom order by comparator: jcr:content/jcr:lastModified
com.day.cq.search.impl.builder.QueryImpl XPath query: //element(*, nt:file)
com.day.cq.search.impl.builder.QueryImpl filtering predicates: {nodename=nodename: nodename=*.jar}
com.day.cq.search.impl.builder.QueryImpl query execution took 272 ms
Javadoc | 説明 |
---|---|
com.day.cq.search | 基本 Query Builder とクエリ API |
com.day.cq.search.result | 結果 API |
com.day.cq.search.facets | ファセット |
com.day.cq.search.facets.buckets | バケット(ファセット内に含まれる) |
com.day.cq.search.eval | 述語エバリュエーター |
com.day.cq.search.facets.extractors | ファセット抽出(評価演算子用) |
com.day.cq.search.writer | Query Builder サーブレット用の JSON Result Hit Writer(/bin/querybuilder.json ) |