アセット共有の Query Builderの機能は、Java API と REST API を通して公開されます。ここでは、これらの API について説明します。
サーバー側 Query Builder(QueryBuilder)はクエリーの記述を受け入れ、XPath クエリーを作成して実行します。オプションで結果セットのフィルタリング、必要に応じてファセットの抽出もおこないます。
クエリーの記述は、単に述語(Predicate)のセットです。サンプルには、1 つのフルテキスト述語(XPath の jcr:contains() 関数に対応)と、1 つの画像サイズ述語(DAM アセットサブツリー内の幅と高さのプロパティを検索)が含まれています。
各述語タイプに、1 つのエバリュエーターコンポーネント(PredicateEvaluator)があります。これらのコンポーネントは、XPath、フィルタリングおよびファセットの抽出に対してその特定の述語を処理する方法を理解しています。OSGi コンポーネントのランタイムによってプラグインされる、カスタムのエバリュエーターを作成するのは簡単です。
REST API を使用すると、JSON で送信される応答を使用した HTTP によって、まったく同じ機能にアクセスできます。
注意:
QueryBuilder API は JCR API を使用して構築されています。また、OSGi バンドル内から JCR API を使用して、Adobe Experience Manager JCR をクエリーすることもできます。詳しくは、JCR API を使用した Adobe Experience Manager データのクエリーを参照してください。
以下のサンプルは、Java プロパティのスタイル表記法で示されています。これらのサンプルを Java API で使用するには、この後の API サンプルのように Java HashMap を使用します。
QueryBuilder JSON サーブレットについては、各例にローカルの CQ インストールへのリンク(デフォルトは http://localhost:4502)が含まれています。これらのリンクを使用する前に、CQ インスタンスにログインする必要があります。
警告:
デフォルトでは、この Query Builder JSON サーブレットは最大 10 件のヒットを表示します。
次のパラメーターを追加すると、サーブレットですべてのクエリー結果を表示できます。
p.limit=-1
注意:
返された JSON データをブラウザーで表示するのに、Firefox 用 JSONView などのプラグインを使用できます。
path=/content 1_property=sling:resourceType 1_property.value=foundation/components/text 1_property.operation=like orderby:path
path=/content 1_property=sling:resourceType 1_property.value=foundation/components/text 1_property.operation=like p.limit=-1 orderby:path
p.guessTotal パラメーターの目的は、実用最小限の p.offset 値と p.limit 値を組み合わせることによって、表示できる適切な結果数を返すことです。
以下のクエリーに p.guessTotal=true を追加して、どのように機能するかを見てみましょう。
path=/content 1_property=sling:resourceType 1_property.value=foundation/components/text 1_property.operation=like p.guessTotal=true orderby:path
"success": true, "results": 10, "total": 10, "more": true, "offset": 0,
AEM 6.0 SP2 の時点では、数値を使用してカスタムの最大結果数までカウントアップすることもできます。上記と同じクエリーを使用して、p.guessTotal の値を 50 に変更してみます。
このクエリーは、同じデフォルトの制限である 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 パラメーターの制限が増やされます。
- total=43、more=false - 合計ヒット数が 43 であることを意味します。UI には先頭ページの一部として 10 件の結果が表示され、続く 3 ページのページネーションが提供されます。この実装を使用して、「43 件の結果が見つかりました」のような説明テキストを表示することもできます。
UI が無限スクロールを使用する必要がある場合は、Query Builder によって正確なヒット数が決定されないように、guessTotal も使用する必要があります。
type=nt:file nodename=*.jar orderby=@jcr:content/jcr:lastModified orderby.sort=desc
type=cq:Page orderby=@jcr:content/cq:lastModified
type=cq:Page orderby=@jcr:content/cq:lastModified orderby.sort=desc
fulltext=Management orderby=@jcr:score orderby.sort=desc
type=cq:Page tagid=marketing:interest/product tagid.property=jcr:content/cq:tags
明確なタグ ID がわかっている場合は、例にあるように tagid 述語を使用します。
タグタイトルのパス(スペースなし)には、tag 述語を使用します。
前の例では、ページ(cq:Page ノード)を検索しているので、tagid.property 述語にはそのノードからの相対パス(jcr:content/cq:tags)を使用する必要があります。デフォルトでは、tagid.property は、単に cq:tags となります。
fulltext=Management group.p.or=true group.1_path=/content/geometrixx/en/company/management group.2_path=/content/geometrixx/en/company/bod
このクエリーでは、クエリー内のサブ式を区切る役目を果たす「グループ」(group)を使用しているので、標準の表記法よりも多くの括弧が含まれています。例えば、前の例は、次のように、よりわかりやすいスタイルで表現することができます。
"Management" and ("/content/geometrixx/en/company/management" or "/content/geometrixx/en/company/bod")
例にあるグループの内部では、path 述語が複数回使用されています。この述語の 2 つのインスタンスの区別と順序付け(一部の述語では順序付けが必要です)をおこなう場合は、述語にプレフィックス N_ を付けます。N は順序を表すインデックスです。前の例では、こうして得られた述語は、1_path および 2_path です。
p.or 内の p は特殊な区切り文字で、後に続くもの(このケースでは or)がグループのパラメーターであることを示します。これは、グループのサブ述語(1_path など)とは対照的です。
p.or が指定されない場合、すべての述語は AND で連結されます。つまり、各結果がすべての述語を満たすことが必要になります。
注意:
異なる述語に対してであっても、単一のクエリー内で同じ数値のプレフィックスを使用することはできません。
type=cq:PageContent property=cq:template property.value=/apps/geometrixx/templates/homepage
type=cq:Page property=jcr:content/cq:template property.value=/apps/geometrixx/templates/homepage
type=cq:Page 1_property=jcr:content/cq:template 1_property.value=/apps/geometrixx/templates/homepage 2_property=jcr:content/jcr:title 2_property.value=English
property=jcr:title property.1_value=Products property.2_value=Square property.3_value=Events
property=jcr:title property.and=true property.1_value=test property.2_value=foo property.3_value=bar
デフォルトでは、次の JSON サーブレットは検索結果内の各ノードに関するデフォルトのプロパティのセット(path、name、title など)を返します。QueryBuilder
返されるプロパティを制御するために、次のいずれかの操作を実行できます。
p.hits=full
を指定します。この場合、各ノードのすべてのプロパティが含まれるようになります。
http://localhost:4502/bin/querybuilder.json?p.hits=full&property=jcr%3atitle&property.value=Triangle
property=jcr:title property.value=Triangle p.hits=full
property=jcr:title property.value=Triangle p.hits=selective p.properties=sling:resourceType jcr:primaryType
他に実行可能な方法として、次の応答に子ノードを含めることができます。QueryBuilder
そのためには、p.nodedepth=n
を指定する必要があります。n はクエリーを返すレベルを表す数値です。子ノードが返されるようにするには、次のプロパティセレクターでそのように指定する必要がありますのでご注意ください。p.hits=full
次に例を示します。
property=jcr:title property.value=Triangle p.hits=full p.nodedepth=5
述語の詳細については、*PredicateEvaluator クラスの Javadoc ドキュメントを参照してください。これらのクラスの Javadoc ドキュメントには、使用できるプロパティのリストが含まれています。
クラス名のプレフィックス(SimilarityPredicateEvaluator の「similar」など)は、クラスのプリンシパルプロパティです。このプロパティは、クエリー内で使用する述語の名前(小文字で使用)でもあります。
このようなプリンシパルプロパティの場合は、クエリーを短縮して、完全修飾バリアント "similar.similar=/content/en" の代わりに "similar=/content/en" を使用できます。完全修飾形式は、クラスのプリンシパルプロパティではないすべてのプロパティに対して使用する必要があります。
String fulltextSearchTerm = "Geometrixx"; // 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 ); }
注意:
QueryBuilder API を使用する OSGi バンドルを作成し、その OSGi バンドルを Adobe Experience Manager アプリケーション内で使用する方法については、Query Builder API を使用する Adobe CQ OSGi バンドルの作成を参照してください。
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
Query loadedQuery = builder.loadQuery("/mypath/getfiles", session);
Query Builder のクエリーを試してみたり、デバッグしたりする場合は、次の URL にアクセスして、QueryBuilder のデバッガーコンソールを使用できます。
http://localhost:4502/libs/cq/search/content/querydebug.html
または、次の URL にアクセスして、QueryBuilder JSON サーブレットを使用することもできます。
http://localhost:4502/bin/querybuilder.json?path=/tmp
(path=/tmp は単なる例です)
注意:
ロガーの設定については、独自のロガーとライターの作成の節で説明します。
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=Geometrixx, relPath=jcr:content} {2_fulltext=fulltext: fulltext=Geometrixx, 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, "Geometrixx") or jcr:contains(jcr:content/@cq:tags, "Geometrixx"))] 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 | 基本の QueryBuilder と Query API |
com.day.cq.search.result | 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 | QueryBuilder サーブレット(/bin/querybuilder.json)用の JSON 結果ヒットライター |