查询生成器优惠了一种查询AEM内容存储库的简单方法。 该功能通过Java API和REST API公开。 本文档介绍这些API。
服务器端查询构建器(QueryBuilder
)将接受查询描述,创建并运行XPath查询,有选择地过滤结果集,如果需要还提取彩块化。
查询描述只是一组谓词(Predicate
)。 例如,全文谓词与XPath中的jcr:contains()
函数相对应。
对于每个谓词类型,都有一个计算器组件(PredicateEvaluator
),它知道如何处理XPath、筛选和facet提取的特定谓词。 创建自定义求值器非常容易,它们通过OSGi组件运行时插入。
REST API通过HTTP提供对完全相同功能的访问,并在JSON中发送响应。
QueryBuilder API是使用JCR API构建的。 您还可以从OSGi捆绑包中使用JCR API查询AEM JCR。 有关信息,请参阅使用JCR API查询Adobe Experience Manager数据。
AEM Gemsis公司由Adobe专家向Adobe Experience Manager公司进行了一系列深入的技术开发。
您可以查看专用于查询生成器的会话,以了解该工具的概述和使用。
这些范例以Java属性样式表示法提供。 要将它们与Java API一起使用,请使用Java HashMap
,如下面的API范例中所示。
对于QueryBuilder
JSON Servlet,每个示例都包含一个指向AEM安装的示例链接(默认位置为http://<host>:<port>
)。 请注意,您必须先登录AEM实例,然后才能使用这些链接。
默认情况下,查询构建器JSON servlet最多显示10次点击。
添加以下参数后,servlet将显示所有查询结果:
p.limit=-1
要在浏览器中视图返回的JSON数据,您可能需要使用插件,如JSONView for Firefox。
以下查询将返回十个结果(或精确到最多十个结果),但通知您实际可用的命中次数::
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引擎和索引。 当有数十万个结果时(无论是执行时间还是内存使用),这可能是一个显着的差异。
该参数的缺点是用户看不到确切的总数。 但是,您可以设置一个像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
该查询将返回10
结果的p.limit
默认值,其偏移值为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,
默认情况下,查询生成器还会提供点击次数。 由于确定准确计数涉及检查每个结果以确定访问控制,因此,这可能需要很长时间。 大多数情况下,该总数用于为最终用户UI实现分页。 由于确定准确计数可能会很慢,建议使用guessTotal功能来实施分页。
例如,UI可以调整以下方法:
获取并显示命中总数(SearchResult.getTotalMatches()或querybuilder.json
响应中的总数)小于或等于100的准确计数;
调用查询生成器时,将guessTotal
设置为100。
该响应可能具有以下结果:
total=43
, more=false
-指示点击总数为43。UI在第一页中最多可显示十个结果,并为后三页提供分页。 您还可以使用此实现显示描述性文本,如"43 results found"。total=100
, more=true
-指示点击总数大于100且不知道确切计数。UI在第一页中最多可显示10个,并为接下来的10个页面提供分页。 您还可以使用它显示文本,如“找到100个以上结果”。 当用户转到下一页时,对查询生成器的调用将增加guessTotal
以及offset
和limit
参数的限制。guessTotal
还应用于UI需要使用无限滚动的情况,以避免查询生成器确定确切的点击计数。
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(名为group
),它用于在查询中限定子表达式,就像括号在更多标准符号中所做的那样。 例如,以前的查询可能以更熟悉的样式表示:
"Experience" and ("/content/wknd/us/en/magazine" or "/content/wknd/us/en/adventures")
在示例中的组中,path
谓词被多次使用。 要区分谓词的两个实例并对其进行排序(某些谓词需要排序),您必须在谓词前加上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
当多次使用属性谓词时,您必须再次添加编号前缀:
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
要避免在搜索属性("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 Servlet将为搜索结果中的每个节点返回一组默认属性(如路径、名称、标题等)。 要控制返回的属性,您可以执行下列操作之一:
指定
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
您还可以做的另一件事是在查询生成器响应中包含子节点。 为此,您需要指定
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
有关更多谓词,请参阅“查询生成器谓词引用”页。
您还可以检查PredicateEvaluator
类](https://helpx.adobe.com/cn/experience-manager/6-5/sites/developing/using/reference-materials/javadoc/com/day/cq/search/eval/PredicateEvaluator.html)的[ Javadoc。 这些类的Javadoc包含可使用的属性列表。
类名称的前缀(例如,SimilarityPredicateEvaluator
中的similar
)是类的principal属性。 此属性也是要在查询中使用的谓词的名称(小写)。
对于此类主体属性,您可以缩短查询并使用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 );
}
使用查询生成器(JSON)Servlet通过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);
要播放和调试查询生成器查询,可以使用查询生成器调试器控制台(位于
http://<host>:<port>/libs/cq/search/content/querydebug.html
或者,查询构建器JSON servlet位于
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查询生成器调试器生成可解释的XPath查询。
非查询生成器查询(XPath、JCR-SQL2)可直接提供给“说明查询”。
日志记录文档中介绍了日志记录器的配置。
执行上一节测试和调试:中所述的查询时,查询生成器实现的日志输出(INFO级别)
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 | 基本查询构建器和查询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 | Facet提取器(用于计算器) |
com.day.cq.search.writer | 查询生成器Servlet的JSON结果命中程序(/bin/querybuilder.json ) |