Hibernate Search is a library that integrates Hibernate ORM with Apache Lucene or Elasticsearch by automatically indexing entities, enabling advanced search functionality: full-text, geospatial, aggregations and more. For more information, see Hibernate Search on hibernate.org.

We just published Hibernate Search 6.2.0.Beta1, a beta release of the next minor version of Hibernate Search.

This version brings highlighting in the Search DSL, indexing plan filters to suspend automatic indexing, an Elasticsearch schema export tool, mapping annotations for constructor parameters when using @ProjectionConstructor, and .missing().lowest()/.missing().highest() options in sorts.

6.2.0.Beta1 also includes many bugfixes and improvements, compatibility with Elasticsearch 8.8 and OpenSearch 2.7, an upgrade of -orm6 artifacts to Hibernate ORM 6.2.4.Final, and more.

What’s new

Hibernate Search 6.2 is still in development: some features are still incomplete or may change in a backward-incompatible way.

Dependency upgrades

Hibernate ORM (HSEARCH-4860)

Hibernate Search now depends on Hibernate ORM 6.2.4.Final for -orm6 artifacts.

Elasticsearch (HSEARCH-4857)

The Elasticsearch backend now works with Elasticsearch 8.8 as well as other versions that were already compatible.

OpenSearch (HSEARCH-4850)

The Elasticsearch backend now works with OpenSearch 2.7 as well as other versions that were already compatible.

Others

Highlighting

With HSEARCH-2192, Hibernate Search now offers a new feature in the Search DSL: highlighting.

Highlighting is a projection that returns fragments from full-text fields of matched documents that caused a query match. Specific terms that caused the match are "highlighted" with a pair of opening and closing tags. It can help a user to quickly identify the information they were searching for on a results page.

For example, one can enable highlighting on a full-text field like this:

@Entity
@Indexed
public class Book {
    @Id
    private Integer id;

    @FullTextField(analyzer = "english")
    private String title;

    @FullTextField(analyzer = "english", highlightable = Highlightable.ANY)
    private String description;
}

And then retrieve highlights like this:

SearchSession searchSession = /* ... */

List<List<String>> result = searchSession.search( Book.class )
        .select( f -> f.highlight( "description" ) )
        .where( f -> f.match().field( "description" ).matching( "robot" ) )
        .fetchHits( 20 );

Which can for example return the following highlights:

# Hit #0
["A <em>robot</em> becomes self-aware."]
# Hit #1
["A <em>robot</em> helps investigate a murder on an extrasolar colony.",
 "On this planet, <em>robots</em> are used extensively."]
# etc.

This is a simple example, but highligting can be configured extensively. See this section of the reference documentation for more information.

Indexing plan filters

With HSEARCH-168/HSEARCH-1383, Hibernate Search now allow enabling/disabling indexing in indexing plans (which include in particular automatic indexing), both fully (for all types) or on a per-type basis.

For example, the following will disable automatic indexing for future changes on all instances of the class Company, except for instances of its subclass Customer:

SearchMapping searchMapping = /* ... */
searchMapping.indexingPlanFilter(
        ctx -> ctx.exclude( Company.class )
                .include( Customer.class )
);

Indexing plan filters can also be configured per-session (though limitations apply when using the outbox-polling coordination strategy):

SearchSession searchSession = /* ... */
searchSession.indexingPlanFilter(
        ctx -> ctx.exclude( Company.class )
                .include( Customer.class )
);

Mapping annotations for constructor parameters when using @ProjectionConstructor

HSEARCH-4574 adds mapping annotations for constructor parameters when using @ProjectionConstructor.

This means in particular you can now project to other things than just fields when using @ProjectionConstructor, for example the entity identifier:

@ProjectionConstructor
public record MyBookIdAndTitleProjection(
        @IdProjection (1)
        Integer id,
        String title (2)
) {
}
1 Projects to the entity identifier (explicit projection through an explicit annotation)
2 Projects to field title (implicit projection)

But this also allows configuring field projections more precisely, for example setting the path of a field projection to something else than just the name of the constructor parameter:

@ProjectionConstructor
public record MyBookTitleAndAuthorNamesProjection(
        @FieldProjection (1)
        String title,
        @FieldProjection(path = "authors.lastName") (2)
        List<String> authorLastNames
) {
}
1 Projects to field title (path derived from the name of the constructor parameter)
2 Projects to field authors.lastName (explicit path)

See this section of the reference documentation for more information about this feature in general, and the documentation of each projection for more information about each available annotation.

Search DSL improvements

.missing().lowest()/.missing().highest() options in sorts (HSEARCH-4149)

When sorting on a field that may not have a value for some documents, it was already possible to use .missing().first()/.missing().last() to tell Hibernate Search to put such documents in first/last position (respectively), regardless of sorting order (ascending/descending).

It is now possible, as an alternative, to use .missing().lowest()/.missing().highest() to tell Hibernate Search to consider such documents as having the lowest/highest value (respectively), taking into account sorting order (ascending/descending):

  • .missing().lowest() puts documents with no value in the first position when using ascending order or in the last position when using descending order.

  • .missing().highest() puts documents with no value in the last position when using ascending order or in the first position when using descending order.

This is mostly useful when the position of missing values is hardcoded, but the sort order is given by the user:

SortOrder orderFromUser = /* ... */;
List<Book> hits = searchSession.search( Book.class )
        .where( f -> f.matchAll() )
        .sort( f -> f.field( "pageCount" ).missing().lowest().order( orderFromuser ) )
        .fetchHits( 20 );

Elasticsearch schema export

It is now possible to export the Elasticsearch schema that Hibernate Search expects to JSON files on the filesystem:

SearchSchemaManager schemaManager = searchSession.schemaManager();
schemaManager.exportExpectedSchema( Path.of( "mydirectory" ) );

The code above will result in a directory tree similar to this:

# For the default backend: backend/indexes/<index-name>/<file>
mydirectory/backend/indexes/customer/create-index.json
mydirectory/backend/indexes/customer/create-index-query-params.json
mydirectory/backend/indexes/order/create-index.json
mydirectory/backend/indexes/order/create-index-query-params.json
# For additional named backends: backend/<backend-name>/indexes/<index-name>/<file>
mydirectory/backends/auth/indexes/user/create-index.json
mydirectory/backends/auth/indexes/user/create-index-query-params.json
mydirectory/backends/auth/indexes/usergroup/create-index.json
mydirectory/backends/auth/indexes/usergroup/create-index-query-params.json

Other improvements and bug fixes

  • HSEARCH-4808: Added a new configuration option for the Elasticsearch client’s connection keep-alive: hibernate.search.backend.max_keep_alive.

  • HSEARCH-4772: Reporting of non-fatal failures during mass indexing is now limited to a certain number of failures, which will prevent those failures from flooding the logs. The limit can be customized with MassIndexer#failureFloodingThreshold(long).

  • HSEARCH-4843: The various module-specific EntityReference interfaces are now deprecated; use the common org.hibernate.search.engine.common.EntityReference instead.

  • HSEARCH-4827: The object projection will no longer allow inner projections that are not affected by nesting (e.g. id, score, …​).

  • HSEARCH-4803: Hibernate Search will now properly ignore internal ServiceConfigurationErrors when appropriate.

  • HSEARCH-4825: Hibernate Search-generated Elasticsearch dynamic templates will now be merged with those defined by custom mappings, instead of being erased as soon as a custom mapping are defined (even if those didn’t mention any dynamic templates).

  • HSEARCH-4853: Hibernate Search will now properly handle canonical record constructors used as projection constructors on JDK 21-ea+21 and above.

And more. For a full list of changes since the previous releases, please see the release notes.

How to get this release

All details are available and up to date on the dedicated page on hibernate.org.

Getting started, migrating

For new applications, refer to the getting started guide:

For existing applications, Hibernate Search 6.2 is a drop-in replacement for 6.1, assuming you also upgrade the dependencies. Information about deprecated configuration and API is included in the migration guide.

Feedback, issues, ideas?

To get in touch, use the following channels:


Back to top