Bootstrap a Query Using the Fluent Search API
Info: Available since brXM 11.1.0.
Overview
This page describes how to initialize a search query using the Fluent Query API in the delivery tier of Bloomreach Content.
When to Use
Use the Fluent Search API when you need to construct and execute search queries in the delivery tier (HST) of Bloomreach Content, either within HST components or JAX-RS service resources.
Prerequisites
- brXM 11.1.0 or later
- Familiarity with HST components or JAX-RS resources
- Access to the delivery tier codebase
Implementation
Create an HstQuery Using HstQueryBuilder
You can create an HstQuery instance from the current request context using HstQueryBuilder. This approach works in both HST components and JAX-RS Service Resources.
In an HST Component
public class LatestItems extends BaseComponent { @Override public void doBeforeRender(HstRequest request, HstResponse response) { final HippoBean scope = RequestContextProvider.get().getSiteContentBaseBean(); final HstQuery hstQuery = HstQueryBuilder.create(scope) .ofTypes(BaseDocument.class) .build(); // ... } }
In a JAX-RS Service Resource
ProductPlainResource extending AbstractResource:
@Path("/products/") public class ProductPlainResource extends AbstractResource { @GET @Path("/{productType}/") public List<ProductRepresentation> getProductResources(....) { final HippoBean scope = RequestContextProvider.get().getSiteContentBaseBean(); final HstQuery hstQuery = HstQueryBuilder.create(scope) .ofTypes(BaseDocument.class) .build(); // ... } }
Without a HstRequestContext
If you do not have a HstRequestContext (for example, in background processes or external integrations), use the HstQueryManager to build an HstQuery. Call HstQueryBuilder#build(HstQueryManager):
Repository repo = HstServices.getComponentManager().getComponent(Repository.class.getName()); Credentials creds = HstServices.getComponentManager().getComponent(Credentials.class.getName() + ".default"); ContentBeansTool cbt = HstServices.getComponentManager().getComponent(ContentBeansTool.class.getName()); Session session = null; try { session = repo.login(creds); HstQueryManager queryManager = cbt.createQueryManager(session); final Node scope = JcrUtils.getNodeIfExists("/content/documents/myproject", session); final HstQuery hstQuery = HstQueryBuilder.create(scope) .ofTypes("myproject:news") .build(queryManager); // ... } finally { if (session != null) session.logout(); }
Define Query Scope with HstQueryBuilder
An HstQuery searches content within one or more scopes. Set scopes using HstQueryBuilder#create(HippoBean ... scopeBeans) or HstQueryBuilder#create(Node ... scopeNodes). Both methods accept one or more arguments.
Example: Multiple Scopes with HippoBeans
final HippoBean base = RequestContextProvider.get().getSiteContentBaseBean(); final HippoBean newsFolder = base.getBean("news"); final HippoBean eventsFolder = base.getBean("events"); // Search within both news/ and events/ folders. final HstQuery hstQuery = HstQueryBuilder.create(newsFolder, eventsFolder) .ofTypes(BaseDocument.class) .build();
Example: Multiple Scopes with JCR Nodes
final Session session = RequestContextProvider.get().getSession(); final Node newsFolderNode = JcrUtils.getNodeIfExists("/content/documents/myproject/news", session); final Node eventsFolderNode = JcrUtils.getNodeIfExists("/content/documents/myproject/events", session); // Search within both news/ and events/ folders. final HstQuery hstQuery = HstQueryBuilder.create(newsFolderNode, eventsFolderNode) .ofTypes(BaseDocument.class) .build();
Important:
HstQueryBuilder#create(...) requires at least one non-null argument. If all arguments are null, a RuntimeQueryException is thrown.
Exclude Scopes
You can exclude specific scopes using HstQueryBuilder#excludeScopes(HippoBean ... excludeScopeBeans) or HstQueryBuilder#excludeScopes(Node ... excludeScopeNodes). Both methods accept one or more arguments.
Example: Exclude a HippoBean Scope
final HippoBean base = RequestContextProvider.get().getSiteContentBaseBean(); final HippoBean eventsFolder = base.getBean("events"); // Search base, but exclude events/ folder. final HstQuery hstQuery = HstQueryBuilder.create(base) .excludeScopes(eventsFolder) .ofTypes(BaseDocument.class) .build();
Example: Exclude a Node Scope
final Session session = RequestContextProvider.get().getSession(); final Node baseNode = JcrUtils.getNodeIfExists("/content/documents/myproject", session); final Node eventsFolderNode = JcrUtils.getNodeIfExists("/content/documents/myproject/events", session); // Search base, but exclude events/ folder. final HstQuery hstQuery = HstQueryBuilder.create(baseNode) .excludeScopes(eventsFolderNode) .ofTypes(BaseDocument.class) .build();
Note:
If a bean or node is present in both the scopes (via #create(...)) and in the exclusions (via #excludeScopes(...)), the exclusion takes precedence. All excluded scopes are omitted from the search.
Set Limit and Offset
Always set a limit for your query. If you do not specify a limit, HST defaults to 1000 results, which may impact performance. Set the limit to the number of items you want to retrieve (for example, pageSize). Use an offset to implement pagination.
Example: Pagination
If pageSize = 10 and you want to display the third page (pageIndex = 3):
final HippoBean base = RequestContextProvider.get().getSiteContentBaseBean(); final HstQuery hstQuery = HstQueryBuilder.create(base) .ofTypes(BaseDocument.class) .limit(pageSize) .offset(pageSize * (pageIndex - 1)) .build();
To determine the total number of results (for example, to calculate the number of pages), use HstQueryResult#getTotalSize(). The getSize() method returns the number of results in the current page (up to the limit).
Recommendation:
Always set a limit to the number of items you need. Avoid relying on the default limit for performance reasons.
Sort Results
You can sort query results by one or more properties, in ascending or descending order. Sorting is performed in the order the properties are added. Only properties stored directly on the document can be used for sorting. Properties within Compounds cannot be used for sorting.
Example: Multi-level Sorting
final HippoBean scope = RequestContextProvider.get().getSiteContentBaseBean(); final HstQuery hstQuery = HstQueryBuilder.create(scope) .ofTypes(BaseDocument.class) // Sort by "example:date" descending (newest first) .orderByDescending("example:date") // Then by "example:title" ascending, case insensitive .orderByAscendingCaseInsensitive("example:title") // Then by "hippostdpubwf:publicationDate" descending .orderByDescending("hippostdpubwf:publicationDate") .build(); // ...
The following methods accept one or more field names (varargs):
orderByDescending(String... fieldNames)orderByDescendingCaseInsensitive(String... fieldNames)orderByAscending(String... fieldNames)orderByAscendingCaseInsensitive(String... fieldNames)
Passing multiple field names to one of these methods is equivalent to calling the method multiple times with each field name.
Limitation:
You can only sort on properties that are stored directly on the document. For details, see Sorting search results in a query can only be done on direct properties of Documents.
Verification
- Confirm that queries return the expected results for the defined scopes, limits, offsets, and sorting.
- Use
HstQueryResult#getTotalSize()to verify total result count for pagination.