Show Menu
화제×

쿼리 빌더 API

자산 공유 쿼리 빌더의 기능은 Java API 및 REST API를 통해 노출됩니다. 이 섹션에서는 이러한 API에 대해 설명합니다.
서버측 쿼리 빌더( QueryBuilder )는 쿼리 설명을 수락하고, XPath 쿼리를 만들어 실행하며, 원하는 경우 결과 세트를 필터링하고, 원하는 경우 패싯을 추출합니다.
쿼리 설명은 단순히 예측( Predicate ) 세트입니다. 예에는 XPath의 함수에 해당하는 전체 텍스트 jcr:contains() 조건자가 포함됩니다.
각 조건자 유형에 대해 XPath, 필터링 및 패싯 추출을 위한 특정 조건자를 처리하는 방법을 알고 있는 평가기 구성 요소가 있습니다( PredicateEvaluator ). OSGi 구성 요소 런타임을 통해 연결되는 사용자 정의 평가기를 만드는 것은 매우 쉽습니다.
REST API는 HTTP를 통해 동일한 기능에 대한 액세스 권한을 제공하며 답변은 JSON으로 전송됩니다.
QueryBuilder API 파섹 OSGi 번들 내에서 JCR API를 사용하여 Adobe Experience Manager JCR을 쿼리할 수도 있습니다. 자세한 내용은 JCR API를 사용하여 Adobe Experience Manager 데이터 쿼리를 참조하십시오 .

Gem Session

AEM Gems는 Adobe 전문가가 제공한 Adobe Experience Manager에 대한 일련의 기술 심층 정보입니다. 쿼리 빌더 전용 세션은 도구 개요 및 사용에 유용합니다.
쿼리 빌더에 대한 자세한 개요는 AEM QueryBuilder를 사용하여 손쉽게 만든 AEM Gem 세션 검색 양식을 참조하십시오.

샘플 쿼리

이러한 샘플은 Java 속성 스타일 표기법으로 제공됩니다. Java API와 함께 사용하려면 API 샘플에서와 HashMap 같이 Java를 사용하십시오.
JSON QueryBuilder 서블릿의 경우, 각 예제는 로컬 CQ 설치(기본 위치, http://localhost:4502 )에 대한 링크를 포함합니다. 이러한 링크를 사용하려면 먼저 CQ 인스턴스에 로그인해야 합니다.
기본적으로 쿼리 빌더 json 서블릿은 최대 10개의 히트를 표시합니다.
다음 매개 변수를 추가하면 서블릿이 모든 쿼리 결과를 표시할 수 있습니다.
p.limit=-1
브라우저에서 반환된 JSON 데이터를 보려면 Firefox용 JSONView와 같은 플러그인을 사용할 수 있습니다.

모든 결과 반환

다음 쿼리는 10개의 결과를 ​반환하지만(또는 최대 10개의 정확한) 히트 수를 알려줍니다. 실제로 사용할 수 있습니다.
http://localhost:4502/bin/querybuilder.json?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
orderby=path

동일한 쿼리(매개 변수 사용)는 모든 결과를 p.limit=-1 반환합니다(인스턴스에 따라 숫자가 높을 수 있음).
http://localhost:4502/bin/querybuilder.json?path=/content&1_property=sling:resourceType&1_property.value=foundation/components/text&1_property.operation=like&p.limit=-1&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.guessTotal 매개 변수의 목적은 최소 실행 가능한 p.offset 및 p.limit 값을 결합하여 표시할 수 있는 적절한 결과 수를 반환하는 것입니다. 이 매개 변수를 사용하면 큰 결과 집합을 사용할 때 성능이 개선됩니다. 따라서 전체 합계(예: result.getSize() 호출)를 계산하고 OAK 엔진 및 인덱스로 내릴 때까지 최적화되어 전체 결과 집합을 읽지 않습니다. 실행 시간 및 메모리 사용량 모두 10만 개의 결과가 있을 경우 이 차이가 크게 날 수 있습니다.
매개 변수에 대한 단점은 사용자가 정확한 합계를 볼 수 없다는 것입니다. 그러나 p.guessTotal=1000과 같은 최소 수를 설정할 수 있으므로 항상 최대 1000개까지 읽을 수 있으므로 더 작은 결과 집합에 대한 정확한 합계를 얻을 수 있지만 더 많은 경우 "및 더"만 표시할 수 있습니다.
아래 p.guessTotal=true 쿼리에 추가하여 어떻게 작동하는지 확인하십시오.
http://localhost:4502/bin/querybuilder.json?path=/content&1_property=sling:resourceType&1_property.value=foundation/components/text&1_property.operation=like&p.guessTotal=true&orderby=path
path=/content
1_property=sling:resourceType
1_property.value=foundation/components/text
1_property.operation=like
p.guessTotal=true
orderby=path

쿼리는 p.limit 오프셋을 사용하여 기본적으로 10 0 결과를 반환합니다.
"success": true,
"results": 10,
"total": 10,
"more": true,
"offset": 0,

AEM 6.0 SP2부터 숫자 값을 사용하여 최대 사용자 지정 최대 결과 수를 카운트할 수도 있습니다. 위와 동일한 쿼리를 사용하지만 값을 다음으로 p.guessTotal 50 변경하십시오.
http://localhost:4502/bin/querybuilder.json?path=/content&1_property=sling:resourceType&1_property.value=foundation/components/text&1_property.operation=like&p.guessTotal=50&orderby=path
0개의 오프셋이 있는 10개의 동일한 기본 제한 값으로 숫자를 반환하지만 최대 50개의 결과만 표시됩니다.
"success": true,
"results": 10,
"total": 50,
"more": true,
"offset": 0,

페이지 매김 구현

기본적으로 쿼리 빌더는 히트 수도 제공합니다. 결과 크기에 따라, 정확한 카운트를 결정하려면 액세스 제어를 위한 모든 결과를 확인하는 데 시간이 오래 걸릴 수 있습니다. 대부분 합계는 최종 사용자 UI에 대한 페이지 매김을 구현하는 데 사용됩니다. 정확한 수를 결정할 때 페이지 매김을 구현하려면 guessTotal 기능을 사용하는 것이 좋습니다.
예를 들어 UI는 다음 방법을 적용할 수 있습니다.
  • 총 히트 수(SearchResult.getTotalMatches() SearchResult.html#gettotalmatches 또는 querybuilder.json 응답의 합계)가 100보다 작거나 같은 정확한 히트 수를 가져오고 표시합니다.
  • 쿼리 guessTotal 빌더를 호출할 때 100으로 설정합니다.
  • 응답에는 다음 결과가 있을 수 있습니다.
    • total=43 , more=false - 총 히트 수가 43임을 나타냅니다. UI는 첫 번째 페이지의 일부로 최대 10개의 결과를 표시하고 다음 세 페이지에 대한 페이지 매김을 제공할 수 있습니다. 이 구현을 사용하여 "43개의 결과"와 같은 설명 텍스트를 표시할 수도 있습니다 .
    • total=100 , more=true - 총 히트 수가 100보다 크고 정확한 수를 알 수 없음을 나타냅니다. UI는 첫 번째 페이지의 일부로 최대 10개까지 표시할 수 있으며 다음 10개 페이지에 대한 페이지 매김을 제공합니다. 또한 이 옵션을 사용하여 "100개 이상의 결과"와 같은 텍스트를 표시할 수 있습니다 . 사용자가 Query Builder에 대한 다음 페이지 호출로 이동할 때 guessTotal offset limit 매개 변수의 제한 및 제한이 증가합니다.
guessTotal 쿼리 빌더가 정확한 히트 수를 확인하지 않도록 하기 위해 UI가 무한 스크롤을 사용해야 하는 경우에도 사용해야 합니다.

jar 파일을 찾아 최신 버전부터 주문

http://localhost:4502/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://localhost:4502/bin/querybuilder.json?type=cq:Page&orderby=@jcr:content/cq:lastModified
type=cq:Page
orderby=@jcr:content/cq:lastModified

모든 페이지를 찾아 마지막으로 수정했지만 내림차순으로 정렬합니다.

http://localhost:4502/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://localhost:4502/bin/querybuilder.json?fulltext=Management&orderby=@jcr:score&orderby.sort=desc
fulltext=Management
orderby=@jcr:score
orderby.sort=desc

특정 태그가 지정된 페이지 검색

'http://localhost:4502/bin/querybuilder.json?type=cq:Page&tagid=marketing:interest/product&tagid.property=jcr:content/cq:tags'
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 .

여러 경로에서 검색(그룹 사용)

http://localhost:4502/bin/querybuilder.json?fulltext=Management&group.1_path=/content/geometrixx/en/company/management&group.2_path=/content/geometrixx/en/company/bod&group.p.or=true
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 술어는 여러 번 사용됩니다. 조건자의 두 인스턴스를 구분하고 정렬하려면(일부 예측자에 대해 순서가 필요), 조건자 앞에 N ** 이 _ where *순서​*색인이어야 합니다. 이전 예에서 결과 조건자는 1_path 2_path 입니다.
in p p.or 다음과 같은 그룹의 하위 술어와 달리, 다음 사항(이 경우 or )은 그룹의 매개 변수임을 나타내는 특수 구분 기호입니다 1_path .
아무 조건도 주지 p.or 않으면 모든 예측자가 함께 ANDed로 설정되므로 각 결과는 모든 예측자를 만족시켜야 합니다.
하나의 쿼리에 동일한 숫자 접두사를 사용할 수 없으며 서로 다른 조건자도 사용할 수 없습니다.

속성 검색

여기에서 cq:template 속성을 사용하여 지정된 템플릿의 모든 페이지를 검색합니다.
http://localhost:4502/bin/querybuilder.json?property=cq%3atemplate&property.value=%2fapps%2fgeometrixx%2ftemplates%2fhomepage&type=cq%3aPageContent
type=cq:PageContent
property=cq:template
property.value=/apps/geometrixx/templates/homepage

여기에는 페이지 자체가 아닌 페이지의 jcr:content 노드가 반환되는 단점이 있습니다. 이 문제를 해결하려면 상대 경로로 검색할 수 있습니다.
http://localhost:4502/bin/querybuilder.json?property=jcr%3acontent%2fcq%3atemplate&property.value=%2fapps%2fgeometrixx%2ftemplates%2fhomepage&type=cq%3aPage
type=cq:Page
property=jcr:content/cq:template
property.value=/apps/geometrixx/templates/homepage

여러 속성 검색

속성 조건자를 여러 번 사용할 때는 번호 접두사를 다시 추가해야 합니다.
http://localhost:4502/bin/querybuilder.json?1_property=jcr%3acontent%2fcq%3atemplate&1_property.value=%2fapps%2fgeometrixx%2ftemplates%2fhomepage&2_property=jcr%3acontent%2fjcr%3atitle&2_property.value=English&type=cq%3aPage
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

여러 속성 값 검색

속성()의 여러 값을 검색할 때 큰 그룹을 피하려면 "A" or "B" or "C" property 조건자에 여러 값을 제공할 수 있습니다.
http://localhost:4502/bin/querybuilder.json?property=jcr%3atitle&property.1_value=Products&property.2_value=Square&property.3_value=Events
property=jcr:title
property.1_value=Products
property.2_value=Square
property.3_value=Events

다중 값 속성의 경우, 여러 값이 일치( "A" and "B" and "C" )되도록 요구할 수도 있습니다.
http://localhost:4502/bin/querybuilder.json?property=jcr%3atitle&property.and=true&property.1_value=test&property.2_value=foo&property.3_value=bar
property=jcr:title
property.and=true
property.1_value=test
property.2_value=foo
property.3_value=bar

반품된 항목 수정

기본적으로 QueryBuilder JSON 서블릿은 검색 결과의 각 노드에 대한 기본 속성 세트를 반환합니다(예: 경로, 이름, 제목 등). 반환되는 속성을 제어하려면 다음 중 하나를 수행할 수 있습니다.
지정
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

사용
p.hits=selective

및 가져올 속성을 지정합니다.
p.properties

공백으로 구분:
http://localhost:4502/bin/querybuilder.json?p.hits=selective&property=jcr%3atitle&property.value=Triangle
property=jcr:title
property.value=Triangle
p.hits=selective
p.properties=sling:resourceType jcr:primaryType

또 다른 방법은 QueryBuilder 응답에 하위 노드를 포함하는 것입니다. 이렇게 하려면
p.nodedepth=n

여기서 n 는 쿼리를 반환할 수준 수입니다. 자식 노드를 반환하려면 속성 선택기로 지정해야 합니다
p.hits=full

예:
http://localhost:4502/bin/querybuilder.json?p.hits=full&p.nodedepth=5&property=jcr%3atitle&property.value=Triangle
property=jcr:title
property.value=Triangle
p.hits=full
p.nodedepth=5

추가 설명

더 자세한 설명을 보려면 쿼리 빌더 설명 참조 페이지를 참조하십시오.
Java에서 PredicateEvaluator 확인할 수도 있습니다. 이러한 클래스의 Java에는 사용할 수 있는 속성 목록이 포함되어 있습니다.
클래스 이름의 접두사(예: " similar " in SimilarityPredicateEvaluator )는 클래스의 principal 속성입니다. 이 속성은 쿼리에 사용할 조건자의 이름이기도 합니다(소문자).
이러한 주요 속성의 경우 쿼리를 단축하고 정규화된 변형 " similar=/content/en " 대신 "" similar.similar=/content/en "를 사용할 수 있습니다. 정규화된 양식은 클래스의 모든 비주체 속성에 사용해야 합니다.

쿼리 빌더 API 사용 예

   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를 사용하고 Adobe Experience Manager 애플리케이션 내에서 해당 OSGi 번들을 사용하는 OSGi 번들을 빌드하는 방법에 대한 자세한 내용은 Query Builder API를 사용하는 Adobe CQ OSGi 번들 만들기를 참조하십시오.
JSON(Query Builder) 서블릿을 사용하여 HTTP를 통해 실행되는 동일한 쿼리:
http://localhost:4502/bin/querybuilder.json?path=/content&type=cq:Page&group.p.or=true&group.1_fulltext=Geometrixx&group.1_fulltext.relPath=jcr:content&group.2_fulltext=Geometrixx&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;

메서드를 사용할 때는 해당 메서드가 Query createFile 인수 값에 따라 파일이나 속성으로 보관됩니다. 다음 예제에서는 경로를 파일로 저장하는 방법을 보여 줍니다. Query /mypath/getfiles
builder.storeQuery(query, "/mypath/getfiles", true, session);

이전에 저장한 모든 쿼리는 다음 QueryBuilder#loadQuery 방법을 사용하여 저장소에서 로드할 수 있습니다.
Query loadQuery(String path, Session session) throws RepositoryException, IOException

예를 들어 경로에 Query 저장된 항목을 다음 코드 조각으로 로드할 /mypath/getfiles 수 있습니다.
Query loadedQuery = builder.loadQuery("/mypath/getfiles", session);

테스트 및 디버깅

QueryBuilder 쿼리를 재생하고 디버깅하려면
http://localhost:4502/libs/cq/search/content/querydebug.html
또는 쿼리 빌더 json 서블릿을
http://localhost:4502/bin/querybuilder.json?path=/tmp
( path=/tmp 는 예일 뿐입니다.)

일반 디버깅 권장 사항

로깅(logging)을 통해 설명 가능한 XP 파섹

대상 인덱스 세트에 대해 개발 주기 동안 모든 쿼리를 설명합니다.
  • QueryBuilder에 대한 DEBUG 로그를 사용하여 설명 가능한 기본 XPath 쿼리를 얻을 수 있습니다.
    • https://<serveraddress>:<serverport>/system/console/slinglog로 이동합니다. DEBUG에서 새 로거를 com.day.cq.search.impl.builder.QueryImpl 만듭니다 .
  • 위의 클래스에 대해 DEBUG가 활성화되면 로그는 Query Builder에서 생성된 XPath를 표시합니다.
  • 연결된 QueryBuilder 쿼리의 로그 항목에서 XPath 쿼리를 복사합니다. 예:
    • 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"))]
  • 쿼리 계획을 확인하려면 XPath 쿼리를 XPath 로 설명

Query Builder 디버거를 통해 설명 가능한 XPath 가져오기

  • AEM QueryBuilder 디버거를 사용하여 설명 가능한 XPath 쿼리를 생성합니다.
대상 인덱스 세트에 대해 개발 주기 동안 모든 쿼리를 설명합니다.
로깅(logging)을 통해 설명 가능한 XP 파섹
  • QueryBuilder에 대한 DEBUG 로그를 사용하여 설명 가능한 기본 XPath 쿼리를 얻을 수 있습니다.
    • https://<serveraddress>:<serverport>/system/console/slinglog로 이동합니다. DEBUG에서 새 로거를 com.day.cq.search.impl.builder.QueryImpl 만듭니다 .
  • 위의 클래스에 대해 DEBUG가 활성화되면 로그는 Query Builder에서 생성된 XPath를 표시합니다.
  • 연결된 QueryBuilder 쿼리의 로그 항목에서 XPath 쿼리를 복사합니다. 예:
    • 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"))]
  • XPath 쿼리를 XPath 설명서에 붙여 넣어 쿼리 계획을 가져옵니다.
Query Builder 디버거를 통해 설명 가능한 XPath 가져오기
  • AEM QueryBuilder 디버거를 사용하여 설명 가능한 XPath 쿼리를 생성합니다.
  1. 쿼리 빌더 디버거에 쿼리 빌더 쿼리 쿼리 제공
  2. 검색 실행
  3. 생성된 XPath 얻기
  4. XPath 쿼리를 Explain Query as XPath에 붙여 넣어 쿼리 계획을 구합니다.
쿼리가 아닌 빌더 쿼리(XPath, JCR-SQL2)를 쿼리 설명에 직접 제공할 수 있습니다.
QueryBuilder를 사용하여 쿼리를 디버깅하는 방법에 대한 자세한 내용은 아래 비디오를 참조하십시오.

로깅으로 쿼리 디버깅

로거 구성은 Creating Your Own Logger and Writer에 설명되어 있습니다 .
테스트 및 디버깅에 설명된 쿼리를 실행할 때 쿼리 빌더 구현의 로그 출력(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=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