In this tutorial we will show how we can upgrade our JPA + Maven application by adding Hibernate search functionalities.

Hibernate Search and JPA - part 1

Hibernate search can be used to apply the powerful full text search engines (like Apache Lucene) to your applications. Hibernate search futher address some shortcomings of Apache Lucene since it takes care of index synchronization and manages correctly the transformation from free text queries to domain objects.

Before diving into a simple example we will address a common newbie question: why do we need using Hibernate Search ? couldn't we just use the great Criteria API or plain Queries ?

Traditional Query/Criteria work well in most cases, provided that you know its limitations. For example, consider the following example:

Query query = sessionFactory.getCurrentSession().createQuery("from User u where u.email like :email");
List<User> userList = query.setParameter("email", "john%").list();

This query might perform badly if the amount of data to retrieve is quite large and the attributes searched are not indexed on DB. On the other hand, when using Hibernate Search you can provide "google like" on field input texts which intelligently matches different fields or even Entity types; implementing such a feature with Criteria or SQL is a madness of complexity and won't get you as good results.

 In order to achieve this great functionalities, Hibernate search creates and uses indexes on the fields which will be part of your searches, however the great news is that, once you have created your index, Hibernate will handle all future index udates.

As the documentation says:

By default, every time an object is inserted , updated or deleted through Hibernate, Hibernate Search updates the according Lucene index .

On top of the generated indexes, it can be quite easy to perform data mining, document similarity search, etc.. for example you can build tag clouds without needing your users to actually tag stuff by hand: you already have vectors of frequencies for all terms of your database.

Ok, let's get back to our JPA +maven example, which uses an Employee and Department class. In this example we will suppose that we will perform search queries on the name attribute of the Employee. Here's the domain class:

package com.mastertheboss.domain;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

import org.hibernate.search.annotations.Analyze;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.IndexedEmbedded;
import org.hibernate.search.annotations.Store;

@Entity
@Indexed
public class Employee {
    @Id
    @GeneratedValue
    private Long id;
    
    @Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
    private String name;
    
    @IndexedEmbedded
    @ManyToOne
    private Department department;

    public Employee() {}

    public Employee(String name, Department department) {
        this.name = name;
        this.department = department;
    }
    

    public Employee(String name) {
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Department getDepartment() {
        return department;
    }

    public void setDepartment(Department department) {
        this.department = department;
    }

    @Override
    public String toString() {
        return "Employee [id=" + id + ", name=" + name + ", department="
                + department.getName() + "]";
    }

}

What has changed in the class: at first, we have declared thea persistent class as indexable. This is done by annotating the class with @Indexed (all entities not annotated with @Indexed will be ignored by the indexing process).

Next, the parameter index=Index.YES will ensure that the text will be indexed, while analyze=analyze.YES ensures that the text will be analyzed using the default Lucene analyzer. Usually, This helps if you are using common words like 'a' or 'the' in your searches. We will talk more about analyzers a little later on. The third parameter we specify within @Field, store=Store.NO, ensures that the actual data will not be stored in the index.

Finally, although not used in this example, we might need searching on the embedded Department class (such as the Department name).So we need to add the @IndexEmbedded annotation to the (Department department9 object that refers to the objects which contain the searchable text, and we also need to add the @Field(index=Index.TOKENIZED, store=Store.NO) annotation to the Department fields which are searchable.
package com.mastertheboss.domain;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;

@Entity
public class Department {

    @Id
    @GeneratedValue
    private Long id;

    @Field(index=Index.TOKENIZED, store=Store.NO)
    private String name;
    
    @OneToMany(mappedBy="department",cascade=CascadeType.PERSIST)
    private List<Employee> employees = new ArrayList<Employee>();
    

    public Department() {
        super();
    }
    public Department(String name) {
        this.name = name;
    }
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public List<Employee> getEmployees() {
        return employees;
    }
    public void setEmployees(List<Employee> employees) {
        this.employees = employees;
    }
}

Changes needed in your configuration

As said, Hibernate Search uses the Apache Lucene search engine to do its indexing. To start using Hibernate Search, you’ll need to configure the location of these index files, as well as a search directory provider (we’ll just use the default). This is done in your JPA/Hibernate properties file. In this example we are using JPA so here's your persistence.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<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_2_0.xsd"
    version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">


    <persistence-unit name="persistenceUnit"
        transaction-type="RESOURCE_LOCAL">

        <class>com.mastertheboss.domain.Employee</class>
        <class>com.mastertheboss.domain.Department</class>
        <properties>

            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/mysqldb" />
            <property name="javax.persistence.jdbc.user" value="user" />
            <property name="javax.persistence.jdbc.password" value="password" />

            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />

                        <!-- Hibernate Search configuration -->
            <property name="hibernate.search.default.directory_provider"
                value="filesystem" />
            <property name="hibernate.search.default.indexBase" value="/var/lucene/indexes" />
        </properties>

    </persistence-unit>


</persistence>

 

0
0
0
s2smodern