We just published Hibernate Search 6.2.0.Alpha1, an alpha release of the next minor version of Hibernate Search.
The main feature of this new version is the new Standalone POJO mapper, allowing to map arbitrary objects to an index, even if those objects are not Hibernate ORM entities. This opens the way to custom integrations to your favorite NoSQL datastores!
Beyond that, 6.2.0.Alpha1 also includes mapping of classes/records to projections using @ProjectionConstructor, search DSL improvements (including projections on object fields), compatibility with Elasticsearch 8.3 and OpenSearch 2.0, and more.
Thanks
Thanks to:
-
Marko Bekhta for his work on features and bugfixes in this release.
-
Waldemar Kłaczyński for providing the groundwork for many features of the Standalone POJO Mapper over the past year.
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-4628/HSEARCH-4627)
-
Hibernate Search now depends on Hibernate ORM 5.6.10.Final, or Hibernate ORM 6.1.1.Final for -orm6 artifacts.
- Lucene (HSEARCH-4609)
-
The Lucene backend now uses Lucene 8.11.2.
- Elasticsearch (HSEARCH-4473/HSEARCH-4622)
-
The Elasticsearch backend now works with Elasticsearch 8.3 and 7.17 as well as other versions that were already compatible.
- OpenSearch (HSEARCH-4561/HSEARCH-4562)
-
The Elasticsearch backend now works with OpenSearch 1.3 and 2.0 as well as other versions that were already compatible.
- Others
-
-
HSEARCH-4631: Upgrade to Elasticsearch client 8.3.2
-
HSEARCH-4485: Upgrade to GSON 2.9.0
-
HSEARCH-4486: Upgrade to slf4j 1.7.36
-
HSEARCH-4539: Upgrade to JBeret 1.4.7.Final
-
HSEARCH-4581: Upgrade to Jackson 2.13.3
-
HSEARCH-4598: Upgrade to Reactive Streams 1.0.4
-
HSEARCH-4608: Upgrade to the latest version of Jakarta dependencies in -orm6/-jakarta artifacts
-
HSEARCH-4590: Upgrade to HCANN 6.0.2 for -orm6 artifacts
-
Standalone POJO Mapper
The Standalone POJO Mapper enables mapping arbitrary POJOs to indexes.
Its key feature compared to the Hibernate ORM integration is its ability to run without Hibernate ORM or a relational database. It can be used to index entities coming from an arbitrary datastore or even (though that’s not recommended in general) to use Lucene or Elasticsearch as a primary datastore.
For more information about the Standalone POJO Mapper, see this section of the reference documentation.
To get started with the Standalone POJO Mapper, see this getting started guide.
Mapping index content to custom types (projection constructors)
As of HSEARCH-3927,
Hibernate Search now offers the ability to define projections through the mapping of custom types (typically records),
by applying the @ProjectionConstructor
annotation to those types or their constructor:
@ProjectionConstructor
public record MyBookProjection(String title, List<Author> authors) {
@ProjectionConstructor
public record Author(String firstName, String lastName) {
}
}
Executing such a projection then becomes as easy as referencing the custom type:
List<MyBookProjection> hits = searchSession.search( Book.class )
.select( MyBookProjection.class )
.where( f -> f.matchAll() )
.fetchHits( 20 );
See this section of the reference documentation for more information.
Mapping improvements
As of HSEARCH-4575, all fields are projectable by default with the Elasticsearch backend.
This change was made because making a field projectable doesn’t incur any performance penalty with the Elasticsearch backend.
Since making a field projectable does have an impact on performance with the Lucene backend, the defaults with the Lucene backend didn’t change: Lucene fields still need to be made projectable explicitly.
Search DSL improvements
- Shorter syntax for complex, root boolean predicates (HSEARCH-4520)
-
Instead of
.where( f → f.bool( b → … ) )
, you can now use.where( (f, b) → … )
:MySearchParameters searchParameters = getSearchParameters(); List<Book> hits = searchSession.search( Book.class ) .where( (f, 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 );
The older syntax has been deprecated in favor of the new one.
- Clearer syntax for complex, non-root boolean predicates (HSEARCH-4520)
-
Instead of
f.bool( b → … )
, you can now usef.bool().with( b → … )
:MySearchParameters searchParameters = getSearchParameters(); List<Book> hits = searchSession.search( Book.class ) .where( (f, b) -> { b.must( f.matchAll() ); if ( searchParameters.getGenreFilter() != null ) { b.must( f.match().field( "genre" ) .matching( searchParameters.getGenreFilter() ) ); } if ( !searchParameters.getAuthorFilters().isEmpty() ) { b.must( f.bool().with( b2 -> { for ( String authorFilter : searchParameters.getAuthorFilters() ) { b2.should( f.match().fields( "authors.firstName", "authors.lastName" ) .matching( authorFilter ) ); } } ) ); } } ) .fetchHits( 20 );
The older syntax has been deprecated in favor of the new one.
- Clearer syntax for the
nested
predicate (HSEARCH-4499) -
Instead of
f.nested().objectField( … ).nest( f.bool().must( … ) )
, you can now usef.nested( … ).must( … )
:List<Book> hits = searchSession.search( Book.class ) .where( f -> f.nested( "authors" ) .must( f.match().field( "authors.firstName" ) .matching( "isaac" ) ) .must( f.match().field( "authors.lastName" ) .matching( "asimov" ) ) ) .fetchHits( 20 );
The older syntax has been deprecated in favor of the new one.
- New
matchNone
predicate (HSEARCH-4489) -
The
matchNone
predicate matches no documents.List<Book> hits = searchSession.search( Book.class ) .where( f -> f.matchNone() ) .fetchHits( 20 );
- New syntax for composite projections (HSEARCH-4498)
-
The definition of composite projections is now possible with a fluent syntax:
List<MyPair<String, Genre>> hits = searchSession.search( Book.class ) .select( f -> f.composite() .from( f.field( "title", String.class ), f.field( "genre", Genre.class ) ) .as( MyPair::new ) ) .where( f -> f.matchAll() ) .fetchHits( 20 );
Most older syntaxes have been deprecated in favor of the new one.
- New
object
projection (HSEARCH-3943) -
The
object
projection yields one projected value for each object in a given object field.List<List<MyAuthorName>> hits = searchSession.search( Book.class ) .select( f -> f.object( "authors" ) .from( f.field( "authors.firstName", String.class ), f.field( "authors.lastName", String.class ) ) .as( MyAuthorName::new ) .multi() ) .where( f -> f.matchAll() ) .fetchHits( 20 );
- New
constant
projection (HSEARCH-4489) -
The
constant
projection returns the same value for every single document, the value being provided when defining the projection.Instant searchRequestTimestamp = Instant.now(); List<MyPair<Integer, Instant>> hits = searchSession.search( Book.class ) .select( f -> f.composite() .from( f.id( Integer.class ), f.constant( searchRequestTimestamp ) ) .as( MyPair::new ) ) .where( f -> f.matchAll() ) .fetchHits( 20 );
outbox-polling
coordination improvements
As of HSEARCH-4533,
you can now customize table names, schema and catalog involved in Hibernate Search’s outbox-polling
coordination strategy
through simple, straightforward configuration properties.
See this section of the reference documentation for more information.
Other improvements and bug fixes
-
HSEARCH-4565: Cyclic dependency detection for IndexingDependency(derivedFrom = …) now detects "buried" cycles.
-
HSEARCH-4580: "_routing" in custom Elasticsearch schema no longer leads to "JsonIOException: JSON document was not fully consumed."
-
HSEARCH-4584: Projection and sort on the same nested field no longer fails with the Lucene Backend.
-
HSEARCH-4619: Boolean predicate now consistently match no documents when not adding any clause, regardless of the backend.
-
HSEARCH-4604: AWS Request signing no longer ignores the target port of the service endpoint.
-
HSEARCH-4483: The default mass indexing monitor (which uses logging) now uses a different format and displays an "instant speed" on top of the overall speed.
-
HSEARCH-4594: Bean references to configurers defined in configuration properties can now be multi-valued, allowing you to apply multiple configurers at once.
-
HSEARCH-4611: A few error messages have been improved, and multi-line error messages are now better indented in Hibernate Search’s failure reports.
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:
-
hibernate-search tag on Stackoverflow (usage questions)
-
User forum (usage questions, general feedback)
-
Issue tracker (bug reports, feature requests)
-
Mailing list (development-related discussions)