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 are excited to announce the release of Hibernate Search 8.0.0.Final.

Compared to the previous 7.2 version it introduces new metric aggregations, compatibility with the latest Elasticsearch and OpenSearch versions, a new Lucene 10 based backend, allows projecting multivalued fields to any container, improves logging by grouping logs into categories, brings a preview of Hibernate Search static metamodel for building search queries with compile-time checks and more! Compared to the previously released 8.0.0.CR1, this version is almost identical, and only adds a few minor dependency updates.

What’s new

For a summary of all new features and improvements since 7.2, head to the dedicated page on hibernate.org, or check a more detailed list below.

Dependency upgrades

Hibernate ORM (HSEARCH-5383)

Hibernate Search targets the Hibernate ORM 7.0 series, which implements Jakarta Persistence 3.2.0. In particular, it is currently based on Hibernate ORM 7.0.0.Final.

Lucene (HSEARCH-5373)

The Lucene-next backend now uses Lucene 10.2.1.

Elasticsearch (HSEARCH-5361)/(HSEARCH-5365)

The Elasticsearch backend works with Elasticsearch 9.0 and 8.18, as well as other already compatible versions.

OpenSearch (HSEARCH-5363

The Elasticsearch backend works with OpenSearch 3.0, as well as other already compatible versions.

Others

Metric aggregations

The Hibernate Search DSL now allows requesting metric aggregations:

AggregationKey<Double> avgPriceKey = AggregationKey.of( "avgPrice" ); (1)
AggregationKey<LocalDate> oldestReleaseKey = AggregationKey.of( "oldestRelease" ); (2)

SearchResult<Book> result = searchSession.search( Book.class )
    .where( f -> f.matchAll() )
    .aggregation( avgPriceKey, f -> f.avg().field( "price", Double.class ) ) (3)
    .aggregation( oldestReleaseKey, f -> f.min().field( "releaseDate", LocalDate.class ) ) (4)
    .fetch( 20 );

Double avgPrice = result.aggregation( avgPriceKey ); (5)
LocalDate oldestRelease = result.aggregation( oldestReleaseKey );
1 Create an aggregation key for an average price aggregation.
2 Create an aggregation key for a minimum date aggregation.
3 Request an .avg() aggregation on the price field. Specifying Double here defines the expected return type of the computed aggregation.
4 Request a .min() aggregation on the release date field. Specifying LocalDate here defines the expected return type of the computed aggregation.
5 Extract the aggregated value from the results.

See the corresponding section on metric aggregations to learn which aggregations are available.

New Lucene backend

While Hibernate Search 8.0 still targets JDK 17, Lucene, starting with version 10, is leveraging new Java APIs, particularly to work with memory, that are available starting with JDK 21. To give users an option to work with the newer Lucene version, Hibernate Search introduces the hibernate-search-backend-lucene-next backend.

Currently, this backend is backed by Lucene 10 and requires JDK 21. In terms of functionality, both Lucene-based backends have the same search capabilities.

See this section of the reference documentation to learn more.

Projecting multivalued fields

It is now possible to use other collection types than List for multivalued projections:

Example 1. Using a Set to collect author names in a projection constructor
@ProjectionConstructor
public record MyBookProjection(
    @IdProjection Integer id,
    String title,
    Set<String> authors) {  (1)
}
1 Using Set as a collection for a multivalued projection.
Example 2. Using the set collector within projection DSL
List<Set<String>> hits = searchSession.search( Book.class )
    .select( f -> f.field( "authors.lastName", String.class ).set() ) (1)
    .where( f -> f.matchAll() )
    .fetchHits( 20 );
1 Using the set collector.

Hibernate Search comes with implementation for most popular collections, but it is also possible to extend it and use a custom collector for an unsupported collection:

List<MyCustomCollection<String>> hits = searchSession.search( Book.class )
    .select( f -> f.field( "authors.lastName", String.class ).collector( new MyCustomCollector() ) ) (1)
    .where( f -> f.matchAll() )
    .fetchHits( 20 );
1 Pass an instance of ProjectionCollector.Provider to the .collector() method.

Logging categories

Hibernate Search now utilizes logging categories instead of FQCNs. It is now easier to enable logging when debugging a particular area of Hibernate Search:

# Set logging level for massindexing events to `TRACE`:
org.hibernate.search.mapper.massindexing=TRACE

See the corresponding section on logging categories to find out which categories are available.

Static metamodel

Hibernate Search’s static metamodel is a new and noteworthy preview feature. We would like for you to give it a try and let us know about your experience with it!

Hibernate Search’s static metamodel is a set of generated classes that represents the structure of each entity’s index, thereby allowing type-safe references to index fields when creating search queries through the Search DSL.

The basic principles are very similar to the JPA static metamodel available in Hibernate ORM, but in the case of Search the metamodel is about indexes rather than entities.

To try out this new feature, add the annotation processor to the build configuration:

<plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <executions>
        <execution>
            <id>default-compile</id>
            <configuration>
                <annotationProcessors>
                    <annotationProcessor>org.hibernate.search.processor.HibernateSearchProcessor</annotationProcessor> (1)
                </annotationProcessors>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.hibernate.search</groupId>
                        <artifactId>hibernate-search-processor</artifactId> (2)
                    </path>
                    <path>
                        <groupId>org.hibernate.search</groupId>
                        <artifactId>hibernate-search-backend-lucene</artifactId> (3)
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </execution>
    </executions>
</plugin>
1 Provide the fully qualified class name of the annotation processor that generates the metamodel.
2 Add the org.hibernate.search:hibernate-search-processor dependency to the annotation processor path (a superset of the compile path), so the Java compiler can find the processor.
3 Add the backend dependency, in this example, the Lucene backend, to the annotation processor path.
The version of both annotation processor and backend dependencies can be omitted in the definition of the annotation paths, because they are defined in the Hibernate Search BOM, which we recommend you import via dependency management. This way the generated metamodel classes will be based on the same backend that the application uses.

And then use the generated metamodel classes to create search queries, e.g.:

SearchSession searchSession = /* ... */; (1)
var scope = Book__.INDEX.scope( searchSession ); (2)

List<Book> hits = searchSession.search( scope )
    .where( f -> f.match()
        .field( Book__.INDEX.title ).field( Book__.INDEX.description ) (3)
        .matching( "robot" ) )
    .fetchHits( 20 );
1 Obtain the search session.
2 Create the search scope over the book index. Using such scope in the Search DSL will automatically limit acceptable field references to the ones obtained from the Book__.INDEX
3 Use the metamodel to reference the fields when creating the queries.

See the corresponding section on static metamodel to find out more.

Other improvements and bug fixes

  • HSEARCH-5385: Adjust projection definition API to be better aligned with its sibling: predicate definition.

  • HSEARCH-5384: Adjust field reference changes in Search DSL APIs to have less impact on existing applications.

  • HSEARCH-5305: Allow vector embeddings up to 16,000 dimensions with the Lucene backends.

  • HSEARCH-5358: Fail faster if an enclosing instance parameter is encountered in a projection constructor on JDK 25+.

  • HSEARCH-5346: ORM mapper now relies on the class details registry provided by Hibernate ORM. Jandex view previously exposed through Hibernate ORM’s bootstrap context is now ignored; integrators should either configure Jandex through Hibernate Models or pass required index views through the mapping configurer.

  • HSEARCH-3204: Better detection of collection changes in the ORM mapper.

  • HSEARCH-5334: Fix possible issue with sorting in the Lucene backend

  • HSEARCH-5342: Improve class loading strategy in the Standalone mapper.

  • HSEARCH-5208: Add a fail-fast configuration option to the mass indexer.

  • HSEARCH-5180: Better mass indexing support for data streams with an initially unknown total size

  • HSEARCH-2945: Update the massindexer monitor API and the default logging implementation.

And more. Please see the release notes for a complete list of changes since the previous releases.

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 8.0 is a drop-in replacement for 7.2, 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