We just published Hibernate Search 6.1.0.Final!
The most important change by far in Hibernate Search 6.1.0.Final
is support for asynchronous, distributed automatic indexing
through the outbox-polling
coordination strategy.
But it doesn’t stop there and introduces Elasticsearch 7.16 compatibility, OpenSearch 1.0/1.2 compatibility, search DSL improvements, conditional mass indexing, and more!
What’s new compared to Hibernate Search 6.0
Dependency upgrades
- Elasticsearch
-
The Elasticsearch backend now works with Elasticsearch 5.6, 6.8, 7.10 or 7.16.
Asynchronous, distributed automatic indexing
While it’s technically possible to use Hibernate Search 6.0 and Elasticsearch in distributed applications, it suffers from a few limitations.
The main goal of Hibernate Search 6.1 is to eliminate these limitations by introducing coordination between application nodes to implement asynchronous, distributed automatic indexing.
Hibernate Search 6.1 introduces the very first coordination strategy: outbox-polling
.
This strategy creates an outbox table in the database to push entity change events to,
and relies on a background processor to consume these events and perform automatic indexing.
Beside eliminating the limitations mentioned above, another advantage of this strategy is that Hibernate Search will no longer trigger lazy-loading or build documents in application threads, which can improve the responsiveness of applications (less work to do on commit).
To learn more about an architecture based on outbox-polling
coordination,
head to this section of the documentation.
You can also get a quick overview of several architectures here.
To jump right in and try the strategy, just set the following property (you will also need to add tables to your database schema):
hibernate.search.coordination.strategy = outbox-polling
Head to this section of the documentation for more information on how to configure coordination.
The You will still be limited to a single application node, but you will benefit from all the other advantages (data safety, increased application responsiveness, …). |
OpenSearch compatibility
Starting with version 6.1, Hibernate Search is also compatible with OpenSearch, the Apache 2.0 licensed fork of Elasticsearch, and regularly tested against versions 1.0 and 1.2.
To use Hibernate Search with OpenSearch, use the same Maven artifacts, configuration and API that you would have used with Elasticsearch.
The only (minor) difference between using Elasticsearch and OpenSearch
is if you configure the Elasticsearch version explicitly:
with OpenSearch, you need to prefix the version with opensearch:
, e.g. opensearch:1.0
.
Search DSL improvements
- New
terms
predicate -
Matches documents for which a given field contains some terms, any or all of them.
Useful for enum-typed fields, in particular.
List<Book> hits = searchSession.search( Book.class ) .where( f -> f.terms().field( "genre" ) .matchingAny( Genre.CRIME_FICTION, Genre.SCIENCE_FICTION ) ) .fetchHits( 20 );
- New
regexp
predicate -
Matches documents for which a given field contains a word matching the given regular expression.
List<Book> hits = searchSession.search( Book.class ) .where( f -> f.regexp().field( "description" ) .matching( "r.*t" ) ) .fetchHits( 20 );
- New
id
projection -
Returns the identifier of the matched entity.
List<Integer> hits = searchSession.search( Book.class ) .select( f -> f.id( Integer.class ) ) .where( f -> f.matchAll() ) .fetchHits( 20 );
- Configurable
.missing()
behavior fordistance
sort -
Distance sorts now allow specifying the behavior when encountering documents with missing values (though only
.missing().first()
/.missing().last()
are supported with Elasticsearch).GeoPoint center = GeoPoint.of( 47.506060, 2.473916 ); List<Author> hits = searchSession.search( Author.class ) .where( f -> f.matchAll() ) .sort( f -> f.distance( "placeOfBirth", center ) .missing().first() ) .fetchHits( 20 );
- Relative field paths
-
The Search DSL now allows creating factories (
SearchPredicateFactory
, etc.) that accept relative field paths.This is mostly useful if you pass factories to reusable methods.
List<Book> hits = searchSession.search( Book.class ) .where( f -> f.bool() .should( f.nested().objectField( "writers" ) .nest( matchFirstAndLastName( f.withRoot( "writers" ), "bob", "kane" ) ) ) .should( f.nested().objectField( "artists" ) .nest( matchFirstAndLastName( f.withRoot( "artists" ), "bill", "finger" ) ) ) ) .fetchHits( 20 ); private SearchPredicate matchFirstAndLastName(SearchPredicateFactory f, String firstName, String lastName) { return f.bool() .must( f.match().field( "firstName" ) .matching( firstName ) ) .must( f.match().field( "lastName" ) .matching( lastName ) ) .toPredicate(); }
Conditional mass indexing
Hibernate Search 6.1 introduces the ability to apply the mass indexer to a subset of your entities, based on an HQL/JPQL "where" clause.
SearchSession searchSession = Search.session( entityManager );
MassIndexer massIndexer = searchSession.massIndexer();
massIndexer.type( Book.class ).reindexOnly( "e.publicationYear <= 2100" );
massIndexer.type( Author.class ).reindexOnly( "e.birthDate < :birthDate" )
.param( "birthDate", LocalDate.ofYearDay( 2100, 77 ) );
massIndexer.startAndWait();
Named predicates
Hibernate Search 6.1 adds named predicates, a way to define the search logic as part of a custom binder/bridge.
This is, in a way, the comeback of the "full-text filters" of Hibernate Search 5.
Custom ES index settings
Starting with Hibernate Search 6.1, you can provide Hibernate Search with JSON files containing the desired settings of your indexes, and Hibernate Search will automatically push these settings when it creates/updates the indexes.
Custom ES index mapping
Starting with Hibernate Search 6.1, you can provide Hibernate Search with JSON files containing part of the desired mapping of your indexes, and Hibernate Search will automatically merge this mapping with the one it generated, so that it gets pushed to Elasticsearch when it creates/updates the indexes.
This is especially useful to set top-level mapping attributes,
for example disabling the _source
field.
Access to Lucene’s IndexReader
Starting with Hibernate Search 6.1, you can now retrieve an IndexReader
when using the Lucene backend:
SearchMapping mapping = Search.mapping( entityManagerFactory );
LuceneIndexScope indexScope = mapping
.scope( Book.class ).extension( LuceneExtension.get() );
try ( IndexReader indexReader = indexScope.openIndexReader() ) {
// work with the low-level index reader:
numDocs = indexReader.numDocs();
}
While generally not necessary, this can be useful for advanced, low-level operations.
Lucene low-level hit caching
Starting with version 6.1,
Hibernate Search allows
configuring the QueryCache
and QueryCachingPolicy
in the Lucene backend,
adding one more performance tweak for advanced Lucene users.
Lucene analyzer definition using tokenizer/filter names
Starting with Hibernate Search 6.1,
a LuceneAnalysisConfigurer
can be implemented without referring to Lucene classes at all,
referring to tokenizers and filters using their name
instead.
This is useful in some modular environments where the application might have access to Hibernate Search classes, but not to Lucene classes.
Jakarta EE
Starting with Hibernate Search 6.1, beside the traditional artifacts targeting Java EE (JPA, CDI, …), Hibernate Search now provides alternative, experimental artifacts that target Jakarta EE 9.1 (Jakarta Persistence 3, Jakarta CDI 3).
These artifacts have their artifact ID suffixed with "-jakarta", similarly to the equivalent artifacts for Hibernate ORM (which you should use together).
The main artifacts (e.g. |
Hibernate ORM 6
Starting with Hibernate Search 6.1, beside the traditional artifacts targeting Hibernate ORM 5.x, Hibernate Search now provides alternative, experimental artifacts that target Hibernate ORM 6 and Jakarta EE 9.1 (Jakarta Persistence 3, Jakarta CDI 3).
These artifacts have their artifact ID suffixed with "-orm6".
The main artifacts (e.g. |
Java modules
Starting with version 6.1, where possible, Hibernate Search now provides multi-release JARs with a full Java module definition that includes all the dependencies.
This excludes the Lucene backend in particular, because Lucene 8 has split packages.
Other improvements and bug fixes
-
HSEARCH-4425: Mark non-nullable properties as such in OutboxPollingOutboxEventAdditionalJaxbMappingProducer
-
HSEARCH-4443: Enum properties in outbox-polling entities (agent, outboxevent) have a weird type in database
-
HSEARCH-4438: More detailed error message for syntax errors in custom mapping/settings file
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.1 is a drop-in replacement for 6.0, assuming you also upgrade other dependencies (e.g. Hibernate ORM). 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)