Automatic indexing of Hibernate ORM entities into Apache Lucene or Elasticsearch. Advanced search API: full-text, geospatial, aggregations and more.

Full-text search for entities

Hibernate Search automatically extracts data from Hibernate ORM entities to push it to local Apache Lucene indexes or remote Elasticsearch/OpenSearch indexes.

It features:

  • Declarative mapping of entity properties to index fields, either through annotations or a programmatic API.

  • On-demand mass indexing of all entities in the database, to initialize the indexes with pre-existing data.

  • On-the-fly listener-triggered indexing of entities modified through a Hibernate ORM session, to always keep the indexes up-to-date.

  • A Search DSL to easily build full-text search queries and retrieve the hits as Hibernate ORM entities.

  • And much more! (see below)

For example, map your entities like this:

@Entity
// This entity is mapped to an index
@Indexed
public class Book {

    // The entity ID is the document ID
    @Id
    @GeneratedValue
    private Integer id;

    // This property is mapped to a document field
    @FullTextField
    private String title;

    @ManyToMany
    // Authors will be embedded in Book documents
    @IndexedEmbedded
    private Set<Author> authors = new HashSet<>();

    // Getters and setters
    // ...
}

@Entity
public class Author {

    @Id
    @GeneratedValue
    private Integer id;

    // This property is mapped to a document field
    @FullTextField
    private String name;

    @ManyToMany(mappedBy = "authors")
    private Set<Book> books = new HashSet<>();

    // Getters and setters
    // ...
}

Index pre-existing data like this:

SearchSession searchSession = Search.session( entityManager );
MassIndexer indexer = searchSession.massIndexer( Book.class );
indexer.startAndWait();

Listener-triggered indexing does not require any change to code based on JPA or Hibernate ORM:

Author author = new Author();
author.setName( "Isaac Asimov" );

Book book = new Book();
book.setTitle( "The Caves Of Steel" );
book.getAuthors().add( author );
author.getBooks().add( book );

entityManager.persist( author );
entityManager.persist( book );

And search like this:

SearchResult<Book> result = Search.session( entityManager )
        .search( Book.class )
        .where( f -> f.match()
                .fields( "title", "authors.name" )
                .matching( "Isaac" ) )
        .fetch( 20 );

List<Book> hits = result.hits();
long totalHitCount = result.total().hitCount();

Full control

Unlike with web search, this is your data, your domain, your application, stored wherever you decide.

You can choose what to index (and how to index it) very precisely with per-property mapping and go even further with custom bridges.

You also have far better control on how your data is processed with configurable analysis, so you can:

  • Tune text processing for specific languages.

  • Tune text processing for domain specific terminology (e.g. medical terms, custom acronyms expansion, …​).

  • Control the ranking process: which results are more important.

Easy yet powerful

Designed to be easy to use from the ground up. Handles schema initialization, indexing and query syntax transparently while you focus on the business side of your search.

The Search DSL exposes many different predicates and sorts through a succinct, easy-to-use API.

And if you need to go beyond, it won’t stop you: native Lucene Queries or Elasticsearch JSON can be inserted right in the middle of Search DSL queries.

Local or distributed

While you’ll find that performance of a "single box" based on Apache Lucene is exceptional, you can also scale out by distributing your application and relying on an Elasticsearch cluster for indexing, with only a few configuration changes.

For even better scaling and coordination with the Elasticsearch backend, Hibernate Search can also send entity change events to a transactional outbox table in the database, spreading indexing across multiple asynchronous event processors.

Spatial queries

Indexing geo-localized entities is as easy as adding the @GenericField annotation.

Filter results around a certain location like the user position, and use a distance sort to pull to the top the matching pizzerias which are closest to the user.

Aggregations

Get search results aggregated by groups and categories.

For example webshops will want to show all hits, but also display a count of hits by price range and brand.

Latest news

Hibernate Search 8.0.0.Alpha3 is out

2025-03-24

We just published Hibernate Search 8.0.0.Alpha3, the third alpha release of the next major version of Hibernate Search. This version includes various adjustments that address recent changes...


Hibernate Search 7.2.3.Final maintenance release

2025-03-18

We are pleased to announce the release of Hibernate Search 7.2.3.Final. This release brings a bug fix and dependency upgrades. What’s new in Hibernate Search 7.2.3.Final Dependency upgrades Hibernate...


Hibernate Search 8.0.0.Alpha2 is out

2025-03-18

We just published Hibernate Search 8.0.0.Alpha2, the second alpha release of the next major version of Hibernate Search. While testing the previous alpha, we’ve identified a few...


Hibernate Search 8.0.0.Alpha1 is out

2024-12-17

We just published Hibernate Search 8.0.0.Alpha1, the first alpha release of the next major version of Hibernate Search. This version brings metric aggregations, logging improvements, a new...


Hibernate Search 7.2.2.Final maintenance release

2024-11-25

We are pleased to announce the release of Hibernate Search 7.2.2.Final. This release brings a couple bug fixes and dependency upgrades. What’s new in Hibernate Search 7.2.2.Final Dependency...


On the safe use of GitHub Actions' <code>pull_request_target</code>

2024-11-12

A few weeks ago, the GitHub Security Lab reported to the Hibernate team a vulnerability in GitHub Actions workflows used in some Hibernate projects, which...


Other news
Back to top