2020-03-21

Hibernate Search - Query DSL-

Executing a search query

// Not shown: get the entity manager and open a transaction

SearchSession searchSession = Search.session( entityManager ); 

SearchResult<Book> result = searchSession.search( Book.class ) 
        .where( f -> f.match() 
                .field( "title" )
                .matching( "robot" ) )
        .fetch( 20 ); 

long totalHitCount = result.getTotalHitCount(); 
List<Book> hits = result.getHits(); 

// Not shown: commit the transaction and close the entity manager
Get a Hibernate Search session, called SearchSession, from the EntityManager.
Initiate a search query on the index mapped to the Book entity.
Define that only documents matching the given predicate should be returned. The predicate is created using a factory f passed as an argument to the lambda expression. See Predicate DSL for more information about predicates.
Build the query and fetch the results, limiting to the top 20 hits.
Retrieve the total number of matching entities.
Retrieve matching entities.
By default, the hits of a search query will be entities managed by Hibernate ORM, bound to the entity manager used to create the search session. This provides all the benefits of Hibernate ORM, in particular the ability to navigate the entity graph to retrieve associated entities if necessary.

The query DSL offers many features, detailed in the following sections. Some commonly used features include:

predicates, the main component of a search query, i.e. the condition that every document must satisfy in order to be included in search results.

fetching the results differently: getting the hits directly as a list, using pagination, scrolling, etc.

sorts, to order the hits in various ways: by score, by the value of a field, by distance to a point, etc.

projections, to retrieve hits that are not just managed entities: data can be extracted from the index (field values), or even from both the index and the database.

aggregations, to group hits and compute aggregated metrics for each group — hit count by category, for example.

Targeting multiple entity types

When multiple entity types have similar indexed fields, it is possible to search across these multiple types in a single search query: the search result will contain hits from any of the targeted types.

Targeting multiple entity types in a single search query

SearchResult<Person> result = searchSession.search( Arrays.asList( 
                Manager.class, Associate.class
        ) )
        .where( f -> f.match() 
                .field( "name" )
                .matching( "james" ) )
        .fetch( 20 ); 

Initiate a search query targeting the indexes mapped to the Manager and Associate entity types. Since both entity types implement the Person interface, search hits will be instances of Person.
Continue building the query as usual. There are restrictions regarding the fields that can be used: see the note below.
Fetch the search result. Hits will all be instances of Person.

Targeting entity types by name

SearchResult<Person> result = searchSession.search( 
                searchSession.scope( 
                        Person.class,
                        Arrays.asList( "Manager", "Associate" )
                )
        )
        .where( f -> f.match() 
                .field( "name" )
                .matching( "james" ) )
        .fetch( 20 ); 

Initiate a search query.
Pass a custom scope encompassing the indexes mapped to the Manager and Associate entity types, expecting those entity types to implement the Person interface (Hibernate Search will check that).
Continue building the query as usual.
Fetch the search result. Hits will all be instances of Person.

Fetching results


In Hibernate Search, the default search result is a little bit more complicated than just "a list of hits". This is why the default methods return a composite SearchResult object offering getters to retrieve the part of the result you want, as shown in the example below.

Getting information from a SearchResult

SearchResult<Book> result = searchSession.search( Book.class ) 
        .where( f -> f.matchAll() )
        .fetch( 20 ); 

long totalHitCount = result.getTotalHitCount(); 
List<Book> hits = result.getHits(); 
// ... 

Start building the query as usual.
Fetch the results, limiting to the top 20 hits.
Retrieve the total hit count, i.e. the total number of matching entities/documents, which could be 10,000 even if you only retrieved the top 20 hits. This is useful to give end users and idea of how many more hits they query produced.
Retrieve the top hits, in this case the top 20 matching entities/documents.
Other kinds of results and information can be retrieved from SearchResult. They are explained in dedicated sections, such as Aggregation DSL.

Getting the total hit count directly

long totalHitCount = searchSession.search( Book.class )
        .where( f -> f.matchAll() )
        .fetchTotalHitCount();
The top hits can also be obtained directly, without going through a SearchResult, which can be handy if only the top hits are useful, and not the total hit count:

Getting the top hits directly

List<Book> hits = searchSession.search( Book.class )
        .where( f -> f.matchAll() )
        .fetchHits( 20 );
If only zero to one hit is expected, it is possible to retrieve it as an Optional. An exception will be thrown if more than one hits are returned.

Getting the only hit directly

Optional<Book> hit = searchSession.search( Book.class )
        .where( f -> f.id().matching( 1 ) )
        .fetchSingleHit();

Getting all hits in a SearchResult

SearchResult<Book> result = searchSession.search( Book.class )
        .where( f -> f.id().matchingAny( Arrays.asList( 1, 2 ) ) )
        .fetchAll();

long totalHitCount = result.getTotalHitCount();
List<Book> hits = result.getHits();

Getting all hits directly

List<Book> hits = searchSession.search( Book.class )
        .where( f -> f.id().matchingAny( Arrays.asList( 1, 2 ) ) )
        .fetchAllHits();


No comments:

Post a Comment