This article covers a Bloomreach Experience Manager version 12. There's an updated version available that covers our most recent release.

Add Constraints to a Query using the Fluent Search API

This feature is available since Hippo CMS 11.1.0.

Introduction

Goal

Add constraints to a search query using the Fluent Search API.

Background

The Fluent Search API in Bloomreach Experience Manager's delivery tier (HST) provides an intuitive way to construct search queries. This page explains how to add constraints to a query.

Add Constraints using HstQueryBuilder

There are cases where you need to apply a constraint to a search query that is not available in the query builder bootstrapping. For example, when querying for the latest 10 news documents that contain some word in the entire document, or some word in the value of a property such as "example:title", you need to apply a constraint to the query.

String query = ....

HippoBean scope = RequestContextProvider.get()
                    .getSiteContentBaseBean()
                    .getBean(relativePathToFolderX);
final HstQuery hstQuery = HstQueryBuilder.create(scope)
        .ofTypes(NewsDocument.class)
        // create and set a constraint,
        // meaning to do full text search by query in the documents.
        .where(constraint(".").contains(query))
        .limit(10)
        .orderByDescending("example:date")
        .build();

HstQueryResult result = hstQuery.execute(); 

In the example above, hstQuery.execute() will return documents that match the free text search query.

Note that for constraints you do not need to do null checks: if in the example above query turns out to be null, the constraint is skipped.

The repository indexes all text in a document, including all of its properties and all the properties of all descendant nodes. To search in all text in a document, specify a relative XPath "." like in the following line from the example above:

.where(constraint(".").contains(query))

You can also search in just a single property, for example:

Search for documents the title of which matches the query string:

        // SNIP
        // only return hits that match the query in the title
        .where(constraint("example:title").contains(query))
        // SNIP

Or in multiple properties, for example:

Search for documents that match query in title AND in summary:

        // SNIP
        // only return hits that match the query in the title AND in the summary
        .where(
                and(
                        constraint("example:title").contains(query),
                        constraint("example:summary").contains(query)
                )
         )
         // SNIP

The two constraints are combined using a logical AND. The code snippet above therefore only returns hits for documents that match the query in the property "example:title" AND the property "example:summary".

Similarly, you can combine constraints using the logical OR as well like the following example:

Search for documents that match query in title OR in summary:

        // SNIP
        // only return hits that match the query in the title OR in the summary
        .where(
                or(
                        constraint("example:title").contains(query),
                        constraint("example:summary").contains(query)
                )
         )
         // SNIP

The above example returns hits for documents that match the query in the property example:title OR the property example:summary.

The preceding examples searched in a property of a document. You can also search in a property of a descendant node (i.e. compound type field) of a document:

        // SNIP
        .where(constraint("example:address/example:street").contains(query))
        // SNIP

As an alternative, you can also specify the first argument as example:address/@example:street, adding @ to mark example:street as a property. Both versions are equivalent.

In addition to #contains(...), more constraints can be applied. The opposite of #contains(...) is #notContains(). These are the only two constraints that involve free text search. The other filter constraints pertain to equality or comparison to a given value.

Tip: import static methods such as constraint(String) from org.hippoecm.hst.content.beans.query.builder.ConstraintBuilder into your component class so you can use them directly in your code:
import static org.hippoecm.hst.content.beans.query.builder.ConstraintBuilder.constraint;
import static org.hippoecm.hst.content.beans.query.builder.ConstraintBuilder.and;
import static org.hippoecm.hst.content.beans.query.builder.ConstraintBuilder.or;
Did you find this page helpful?
How could this documentation serve you better?
On this page
    Did you find this page helpful?
    How could this documentation serve you better?