Mock tests, Interview questions, Tutorials and Tech news
 
 
Home > Programming / tutorials > Hibernate Search – Getting Started

Hibernate Search – Getting Started

Once your dynamic site has gone bigger, data in relational database has grown, there is always a need for searching the contents. SQL queries with like ‘%…%’ are useful. But to do multiple columns / table searching, we’ll need to have big SQL queries with different conditions, ANDed and ORed. Such searching is not realistic and can not be maintained and extended easily.
For Hibernate users, Hibernate search helps searching rows from database. Without writing any complex SQL queries, you can search multiple columns and get related objects from db.

In our site Skill-Guru , you will notice a search box on the right hand side.  We have enabled the search on few tables and columns initially. Currently it will search for the tests , description and keywords for the input keyword.

Hibernate search searches objects from text queries. It uses Apache Lucene Indexing technique. It indexes the tables with the help of annotations. Also it does the synchronization of database and index. Following tutorial demonstrates a simple searching example using hibernate search. The application uses JPA way.

Consider any site selling some products. You want to search products by title, description etc. Consider following products table.

create table product(
id int(5) not null auto_increment,
title varchar(100) not null,
description varchar(250) not null,
manufacture_date datetime,
primary key(id));
To start with Hibernate Search , you must have hibernate search downloaded. Download Hibernate search 3.1.1 and Hibernate 3.
Create a java application and add required jars to your build path. Click here to know exact jars used in this project.

Crate a src/META-INF directory and create a persistence.xml file with following contents (edit it according to your database parameters)

<?xml version=”1.0″ encoding=”UTF-8″?>
<persistence xmlns=”http://java.sun.com/xml/ns/persistence
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation=”http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd” version=”1.0″>

<persistence-unit name=”defaultManager”
transaction-type=”RESOURCE_LOCAL”>
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name=”hibernate.connection.driver_class”
value=”com.mysql.jdbc.Driver” />
<property name=”hibernate.connection.url”
value=”jdbc:mysql://localhost:3306/hibernatetest” ></property>
<property name=”hibernate.connection.username” value=”root” />
<property name=”hibernate.connection.password”
value=”root” />
<property name=”hibernate.show_sql” value=”false” />

<property name=”hibernate.search.default.directory_provider”
value=”org.hibernate.search.store.FSDirectoryProvider” />
<property name=”hibernate.search.indexing_strategy” value=”manual” />
<property name=”hibernate.search.default.indexBase” value=”e:\indexes” />
</properties>
</persistence-unit>
</persistence>

Make sure you have database url, username and password entered properly. Another important factor is the indexBase directory. Hibernate search creates indexes for each table it need to search and those indexes will be saved in this directory.

The properties:
<property name=”hibernate.search.default.directory_provider”
value=”org.hibernate.search.store.FSDirectoryProvider” />
<property name=”hibernate.search.indexing_strategy” value=”manual” />
<property name=”hibernate.search.default.indexBase” value=”e:\indexes” />
are used by Hibernate Search.

Create test.eo package and create a ProductEO class. The ProductEO entity class for products table might look like below:

Create test.eo package and create a ProductEO class. The ProductEO entity class for products table might look like below:

package test.eo;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table(name=”product”)
public class ProductEO {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name=”id”)
private Integer id;

@Column(name=”title”)
private String title;

@Column(name=”description”)
private String description;

@Column(name=”manufacture_date”)
private Date manifactureDate;

public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Date getManifactureDate() {
return manifactureDate;
}
public void setManifactureDate(Date manifactureDate) {
this.manifactureDate = manifactureDate;
}
}

To make this entity to be able to be searched, we need to add some more annotations. Altered Entity class is shown below:

package test.eo;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.search.annotations.DocumentId;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.Store;

@Entity
@Table(name=”product”)
@Indexed
public class ProductEO {

@DocumentId
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name=”id”)
private Integer id;

@Field(index=Index.TOKENIZED, store=Store.NO)
@Column(name=”title”)
private String title;

@Field(index=Index.TOKENIZED, store=Store.NO)
@Column(name=”description”)
private String description;

@Column(name=”manufacture_date”)
private Date manifactureDate;

public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Date getManifactureDate() {
return manifactureDate;
}
public void setManifactureDate(Date manifactureDate) {
this.manifactureDate = manifactureDate;
}
}

We added following:

1. @Indexed annotation to Class
2. @DocumentId annotation on the primary key. Hibernate Search needs to store an id in the index to ensure index uniqueness for a given entity. This annotation marks that unique property. In most of the cases this will be the primary key.
3. @Field(index=Index.TOKENIZED, store=Store.NO) annotation on the fields, which need to be matched while searching. The parameter
index=Index.TOKENIZED will ensure that the text will be tokenized (in short words will be identified) using the default Lucene analyzer. store=Store.NO is to  ensures that the actual data will not be stored in the index.

Now define a HibernateEntitymanagerHelper class in package test.services to initialize persistence context as below:

package test.services;
import javax.persistence.*;
public class HibernateEntitymanagerHelper {
private static EntityManagerFactory emf;
static{
try{
emf = Persistence.createEntityManagerFactory(“defaultManager”);
}catch(Throwable tw){
throw new ExceptionInInitializerError(tw);
}
}
public static EntityManagerFactory getEntityManagerFactory() {
return emf;
}
public static void shutdown() {
emf.close();
}
}

Create following AddProducts  class in test.services package and add some data into the table:

package test.services;

import javax.persistence.EntityManager;
import test.eo.*;
import java.util.Date;

public class AddProducts {
public static void main(String[] args) {
try{
EntityManager em = HibernateEntitymanagerHelper.getEntityManagerFactory().createEntityManager();
em.getTransaction().begin();
ProductEO prodEO = new ProductEO();
prodEO.setTitle(“Mike”);
prodEO.setDescription(“XXX company Mike”);
prodEO.setManifactureDate(new Date());
em.persist(prodEO);

prodEO = new ProductEO();
prodEO.setTitle(“Phone”);
prodEO.setDescription(“YYY company Phone”);
prodEO.setManifactureDate(new Date());
em.persist(prodEO);

prodEO = new ProductEO();
prodEO.setTitle(“Microphone”);
prodEO.setDescription(“YYY company Microphone”);
prodEO.setManifactureDate(new Date());

em.persist(prodEO);
em.getTransaction().commit();

}catch(Exception e){
e.printStackTrace();
}
}
}

Now, this is time to test. For Hibernate search to work you have to trigger an initial Indexing to populate the Lucene index with the data already present in your database.  Following code creates indexes and then does searching.

package test.services;

import java.util.List;

import javax.persistence.EntityManager;
import test.eo.*;
import java.util.Date;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.Search;

public class ProductService {

/**
* @param args
*/
public static void main(String[] args) {

try{
EntityManager em = HibernateEntitymanagerHelper.getEntityManagerFactory().createEntityManager();
FullTextEntityManager fullTextEntityManager =  Search.getFullTextEntityManager(em);

fullTextEntityManager.getTransaction().begin();

List<ProductEO> products = em.createQuery(“select product  from ProductEO as  product”).getResultList();
for (ProductEO product : products) {
fullTextEntityManager.index(product);
System.out.println(“Product”+product.getTitle());
}

String[] fields = new String[]{“title”, “description”};
MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, new StandardAnalyzer());
// parser.setDefaultOperator(QueryParser.AND_OPERATOR);

/*
* Search only by lowercase
*/
org.apache.lucene.search.Query query = parser.parse( “phone” );
// wrap Lucene query in a javax.persistence.Query
javax.persistence.Query persistenceQuery =  fullTextEntityManager.createFullTextQuery(query, ProductEO.class);
// execute search
List<ProductEO> result = persistenceQuery.getResultList();
System.out.println(“result ::”+result);
for (ProductEO product : result) {
System.out.println(“product ::”+product.getTitle());
}

fullTextEntityManager.getTransaction().commit();
em.close();
HibernateEntitymanagerHelper.shutdown();
}catch(Exception e){
e.printStackTrace();
}

}

}

Going for an interview or want to test your hibernate skills , check out our hibernate interview questions

Be Sociable, Share!
  1. Garima
    November 12th, 2012 at 04:51 | #1

    this code is really helpful but it is using only one i.e. product table to search,I am also able to search in one table i.e. Job table using hibernate but when same code I am trying on 2 different tables(Job and User(having same field called (id) as FK)),For Job table I am able to get result,for User table,the results is 0,Kindly tell me how to make lucene search over the entire database.

  2. July 11th, 2012 at 08:57 | #2

    I like your blog, i am geting latest results from your blog thank you admin, thanks for updating best
    results, once again thank you your swapna

  3. slack.br
    April 9th, 2012 at 07:24 | #3

    @Vinay

    Thank you, I will study the example you showed, and try to adapt

    hug

  4. slack.br
    April 8th, 2012 at 07:13 | #4

    @Vinay

    Thank you, I will study and do some tests! :)

    hugs

  5. April 7th, 2012 at 11:33 | #5

    This post could also be helpful. I guess you are looking for something like this http://www.skill-guru.com/blog/2010/07/19/integrting-hibernate-search-with-a-spring-and-jpa-application/

  6. April 7th, 2012 at 11:32 | #6

    This post is about hibernate search. I have already shown you an example of integrating JSF with Spring . Since your service layer consists of Spring and hibernate , you have to pass the search string from view to action and then to service layer. JSF in this case will only act as a medium to pass the data back and forth

  7. slack.br
    April 7th, 2012 at 08:53 | #7

    @Vinay

    Vinay, sorry I explained wrong!
    I need a example to use full text search (hibernate search) using with JSF (or JSP) + mysql. Like this example you showed!

    Do you have any please?

    thank you very much

  8. April 6th, 2012 at 14:31 | #8

    We have some good articles on getting started with JSF
    http://www.skill-guru.com/blog/2009/08/10/jsf-tutorial-for-beginners/
    This will help integrate Springweb flow with JSF
    http://www.skill-guru.com/blog/2010/04/09/spring-webflow-integration-with-jsf/

    There are other examples to integrate JSF with Spring and hibernate

  9. slack.br
    April 5th, 2012 at 14:02 | #9

    Good explanation. I’m trying to get some data in my database (mysql) and display on screen, I need to use your example with JSF.

    Do you have any? researched as much, but I am a beginner, you can not find

    thanks

  10. March 26th, 2012 at 22:29 | #10

    Thanks for sharing this. It is so fortunate to read your blog, filled with knowledgable message.I believe we each can do nonetheless better within the future. it is a great honour for those who visit our website and provides some worthwhile suggestions.many due to the person who wrote this submit,this was very informative for me.please proceed this awesome work.

  11. June 16th, 2011 at 21:26 | #11

    dodo ,search has nothing to do with transaction type.

  12. dodo
    June 16th, 2011 at 02:26 | #12

    Hello

    One novice question, will HibernateSearch work if the TransactionType specified in persistence.xml is JTA instead of RESOURCE_LOCAL?

  13. Federico Vela
    January 31st, 2011 at 12:01 | #13

    How can I annotate one field with the @Id and another with @DocumentId ?
    When I try this setup my index is not populated.
    Any help will be appreciated.
    Thanks!

  14. Peeyush
    July 3rd, 2010 at 22:19 | #14

    Thanks everybody for answering my question. Really appreciable.
    I think we have the approach now in place, it’s now just matter of implementing it.

  15. Sergey
    June 23rd, 2010 at 05:12 | #15

    Could you please explain:
    1. How index should be updated in case of feeds (asynchronous jobs) running on database layer? These feeds change data periodically.
    2. What happens in case of concurrently updating the Lucene index and Hibernate Search transaction querying for data?
    3. Which of the data gets blocked on database during index update and for what period?

  16. June 22nd, 2010 at 21:23 | #16

    Thanks for the explanation Smitha.

  17. smitha
    June 22nd, 2010 at 03:38 | #17

    Thanks Hussain.
    To search on joined tables, define relationship in the EO class and mark relation as @IndexedEmbedded.
    Consider an example of Test and Topics, where a test can have n number of topics covered.
    You can define OneToMany relation as below. Mark this relation @IndexedEmbedded

    @IndexedEmbedded
    @OneToMany
    private List topics= new ArrayList();

    Now if you want to search a test by topic name, then in TopicEO class mark topicName as @Field.

  18. Hussain
    June 19th, 2010 at 23:33 | #18

    Really nice post, one question though, how about if search is based on more than one joined tables.

  19. June 19th, 2010 at 09:07 | #19

    Thank so Aaron for answering Peeyush question. This will be very informative for the readers as well.
    @Peeyush this would answer you question.

  20. June 19th, 2010 at 08:04 | #20

    You can run Hibernate Search in a clustered environment really easily. You designate one node as a master indexer and have it watch a JMS queue. That queue is fed by each of the slave nodes in your cluster; any time data is persisted by any of the nodes, a JMS message is fired off. The master mode receives that notification, reads the data from the db, indexes and places a shared index on a folder shared by all of your nodes. Each node then polls that folder for changes and copies them locally. The file directory provider and JMS listener all are provided by Hibernate Search.

  21. June 17th, 2010 at 23:13 | #21

    Good point Peeyush. We have not tried in clustered environment . But I think in clustered environment, it the is the location of index file that matters.
    I will find more about it.

  22. Peeyush
    June 17th, 2010 at 22:20 | #22

    Quite helpful posting.I have a question related to this.
    How this will work in clustered environment with single database?

  1. June 17th, 2010 at 16:08 | #1
  2. November 1st, 2010 at 08:51 | #2
  3. June 6th, 2012 at 07:30 | #3

Get Adobe Flash playerPlugin by wpburn.com wordpress themes