Query builder in Hibernate Search 6

The Hibernate Search 6 documentation shows one example of how to dynamically generate a single bool() in the where clause:

MySearchParameters searchParameters = getSearchParameters(); 
List<Book> hits = searchSession.search( Book.class )
        .where( f -> f.bool( b -> { 
            b.must( f.matchAll() ); 
            if ( searchParameters.getGenreFilter() != null ) { 
                b.must( f.match().field( "genre" )
                        .matching( searchParameters.getGenreFilter() ) );
            }
            if ( searchParameters.getFullTextFilter() != null ) {
                b.must( f.match().fields( "title", "description" )
                        .matching( searchParameters.getFullTextFilter() ) );
            }
            if ( searchParameters.getPageCountMaxFilter() != null ) {
                b.must( f.range().field( "pageCount" )
                        .atMost( searchParameters.getPageCountMaxFilter() ) );
            }
        } ) )
        .fetchHits( 20 );

1 . How would I modify your above example, from a single bool()
f → f.bool
to conditionally nest multiple bools, using if or for-loops?

2 . Similarly, how can I conditionally decide if I want to add .sort() to the above example, when “if (searchParameters.getGenreFilter() != null)” is true?

Thanks for the assist.

Boolean predicates are just like any other predicate. You can call f.bool() again to create another boolean predicate and nest it.

MySearchParameters searchParameters = getSearchParameters(); 
List<Book> hits = searchSession.search( Book.class )
        .where( f -> f.bool( b -> { 
            b.must( f.matchAll() ); 
            List<Genre> genresFilter = searchParameters.getGenresFilter();
            if ( !genresFilter.isEmpty() ) { 
                b.must( f.bool( b2 -> {
                    for ( Genre genre : genresFilter ) {
                        b2.should( f.match().field( "genre" ).matching( genre ) );
                    } ) );
            }
        } ) )
        .fetchHits( 20 );

And if you have a pre-determined number of clauses, you don’t even need a lambda:

MySearchParameters searchParameters = getSearchParameters(); 
List<Book> hits = searchSession.search( Book.class )
        .where( f -> f.bool( b -> { 
            b.must( f.matchAll() ); 
            GenreFilter genresFilter = searchParameters.getGenresFilter();
            if ( genresFilter != null ) { 
                b.must( f.bool()
                    .should( f.match().field( "genre" )
                                .matching( genresFilter.getGenre1() ) )
                    .should( f.match().field( "genre" )
                                .matching( genresFilter.getGenre2() ) ) );
            }
        } ) )
        .fetchHits( 20 );

This is documented as well:

MySearchParameters searchParameters = getSearchParameters(); 
List<Book> hits = searchSession.search( Book.class )
        .where( f -> f.matchAll() )
        .sort( f -> f.composite( b -> { 
            for ( MySort mySort : searchParameters.getSorts() ) { 
                switch ( mySort.getType() ) {
                    case GENRE:
                        b.add( f.field( "genre_sort" ).order( mySort.getOrder() ) );
                        break;
                    case TITLE:
                        b.add( f.field( "title_sort" ).order( mySort.getOrder() ) );
                        break;
                    case PAGE_COUNT:
                        b.add( f.field( "pageCount" ).order( mySort.getOrder() ) );
                        break;
                }
            }
        } ) )
        .fetchHits( 20 );