Sunday, May 31, 2009

Hibernate Search + Apache Lucene

It worthwhile to say that every Java developer knows about Apache Lucene project. No doubts, the best open source search engine! But today it's not about Apache Lucene, it's about Hibernate Search project, just another excellent library from Hibernate team.

So, what if you need some search capabilities in your application? For sure, it depends on requirements, but let's consider Java application which uses database as back-end and Hibernate as ORM framework. I would suggest a few ways to do search in this case:
1) Implement own search framework based on full text search capabilities of your database server (vendor-locked solution).
2) Implement own search framework with SQL/HQL queries. Works well for very simple scenarios. but is not enough in most cases.
3) Use Hibernate Search (and Apache Lucene). As powerful as Apache Lucene and as flexible as Hibernate framework. The most preferable solution.

From developer point of view, integration of the Hibernate Search is just a matter of additional annotations together with a few configuration lines in hibernate.cfg.xml. Let's start with last one.

<property name="hibernate.search.default.directory_provider">
org.hibernate.search.store.RAMDirectoryProvider
</property>

That tells Hibernate Search to store all indexes in RAM (don't do that on production system!). And ... that's it!

Now let's look on typical persistent entity and ... how to make it searchable!
@Entity
@Indexed
public class User {
private Long id;
private String firstName;
private String lastName;

@Id
@GeneratedValue( strategy = GenerationType.AUTO )
@Column( name = "UserID" )
@DocumentId
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}

@Basic
@Column( name = "FirstName", length = 50 )
@Field( index = Index.UN_TOKENIZED )
public String getFirstName() {
return firstName;
}

public void setFirstName( String firstName ) {
this.firstName = firstName;
}

@Basic
@Column( name = "LastName", length = 50 )
@Field( index = Index.UN_TOKENIZED )
public String getLastName() {
return lastName;
}

public void setLastName( String lastName ) {
this.lastName = lastName;
}
}

A few annotations in bold (@Indexed, @Field, @DocumentId) make all the magic. Hibernate Search provides additional listeners which take care on entity indexing (Lucene documents creation/deletion). In next post I will explain how to search stored entities by specific criteria. For now, I would mention a great book Hibernate Search in Action which perfectly explains all details.