Hibernate Search with Jersey – Lucene Tutorial

This tutorial is to show you how to search and rank your data on relevance using Hibernate.

First of all, the Hibernate documentation does a great job on explaining the full scope of it’s search, but I had to make a few updates to get it working with Jersey.

Okay, so let’s begin. The first thing you are going to want to do is import the libraries to your project. In this example we are using Maven, but Gradle is an option as well.

Using Maven:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-search-orm</artifactId>
    <version>5.5.4.Final</version>
</dependency>
 
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>5.0.9.Final</version>
</dependency>

Next, you are going to want to open up the hibernate.cfg.xml file and a couple of properties to where you want the indexing to be saved. If you are launching this on a server after developing locally, make sure you update this path to a location where you have permissions to write to.

    <property name="hibernate.search.default.directory_provider">filesystem</property>
    <property name="hibernate.search.default.indexBase"><strong>/path/to/directory</strong></property>

Cool. We now have the preliminary stuff set up now it’s time to talk about the code. Can we talk about the code? I’ve been dying to talk about the code! (It’s Always Sunny reference for those of you that think I’m crazy)
tumblr_o8ll4zcpd31sfjwhdo1_500

In this example we will have a User object which we will be performing a search on name. The user will have two fields, id and name. Using annotations we will define the object like so:

@Entity
@Table(name = "user")
@Indexed(interceptor=UserIndexingInterceptor.class)
public class User implements Serializable{
 
    @ApiModelProperty(required = true)
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
 
    @ApiModelProperty(required = true)
    @Basic
    @Field
    private String name;
.....

To make your objects searchable, you need to initialize the indexing like so before performing the search:

Session session = HibernateUtil.getSessionFactory().openSession();
FullTextSession fullTextSession = org.hibernate.search.Search.getFullTextSession(session);
fullTextSession.createIndexer().startAndWait();

Now search is as easy as:

 QueryBuilder qb = fullTextSession.getSearchFactory()
                .buildQueryBuilder().forEntity(User.class).get();
 
        org.apache.lucene.search.Query query = qb
                .bool()
                .must(
                    qb.keyword()
                    .onFields("name")
                    .matching(searchQuery+"*").createQuery())
                .createQuery();
 
        // wrap Lucene query in a org.hibernate.Query
        org.hibernate.Query hibQuery =
                fullTextSession.createFullTextQuery(query, User.class);
 
        // execute search
        List result = hibQuery.list();

We are searching on the field “name” trying to match it to some text. The reason for the star (*) concatenation is to let the algorithm know that it can match characters to the end of the word. So if you’re searching for “Mi” you can match with results such as Mike, Michael, Michelle etc…

Although is is a good starting point, there is a whole science behind this and a ton more to learn. I will try to keep this post updated as I use more aspects of it.
Full documentation can be found here.

Until then, you stay classy San Diego.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>