Saturday, July 11, 2009

Hibernate Search + Apache Lucene (continued)

Let's continue very useful and interesting topic about Hibernate Search and Apache Lucene. In my last post we discovered new annotations which allow persistent entities to be "searchable". In this post I am going to show how to query such entities with various search criteria.

Once entities are annotated, they could be queried with regular Apache Lucene query. Simple flow looks like this:
Session session = sessionFactory.getNewSession();
FullTextSession fullTextSession = Search.getFullTextSession( session );

try {
fullTextSession.beginTransaction();

// query - regular Lucene query, f.e. "author=King"
// entities - list of entity classes, like Entity1.class, Entity2.class, ...

FullTextQuery q = fullTextSession
.createFullTextQuery( query, entities );

// Get a collection of matched entities
Collection< Object > results = q.list();

fullTextSession.getTransaction().commit();
} catch (Exception ex ) {
fullTextSession.getTransaction().rollback();
throw ex;
} finally {
session.close();
}
That's how Hibernate Search makes it simple. The only difference from Hibernate's model is FullTextSession usage. Here are few simple details about how Hibernate Search works on top of Apache Lucene:

  • for each entity class Apache Lucene creates own index

  • Hibernate Search adds a few additional properties (like persistent entity Id and Type) to associate Apache Lucene document and Hibernate entity

  • for each query Hibernate Search uses query rewrite to ensure only indexed properties of a particular entity are present in query

  • entity's (re)indexing occurs when database transaction commits (but Hibernate Search allows you manually (re)index entity)

Hibernate Search also allows you to use very powerful features like filters (with parameters) and sorting. Filters are extremely useful in case of security rules or search with search results implementation.
...
FullTextQuery q = fullTextSession
.createFullTextQuery( query, entities );
.setSort( new Sort(
new SortField[] {
new SortField( "name", false )
}
)
);

// Enable filter with name 'filterName' and parameter 'value' set to value
Object value = ...;
q.enableFullTextFilter( "filterName" )
.setParameter( "value", value );

// Get a collection of matched entities
Collection< Object > results = q.list();
...
It's very simple to integrate and use Hibernate Search into existing applications. It most cases I found integration seamless.

There are a bunch of interesting issues that might occur:

  • how to get all indexed properties for entity?

  • how to reindex whole existing database?

  • how to deploy master/slave(s) configuration?

For those I am going to create dedicated post because an implementation is a little bit tricky (but in general not complicated at all).