Hibernate Search is a full text search engine built using Apache Lucene framework. Hibernate Search indexes your domain model, keep the index upto date and also performs full text search functionality to fetch matching domain objects. This Hello World example shows how you can setup hibernate search and get your domain objects based on free text search query. In this tutorial we will use Maven tool to build the project, Eclipse IDE to code and SQLite database to save our domain objects.
To make the learning easier, I have used SQLite database which is a self-contained, serverless, zero-configuration, transactional SQL database engine. But you are free to choose any other database as well to learn this tutorial. To run example shown in this tutorial, you do not have to install any database or SQLite database seperately. However to browse the database you can use 'SQLite Manager - Firefox addon' which provides a very nice GUI for SQLite database.
Tools and Technologies used in this article :
Hibernate Search 4.1
Maven
SQLite 3 database
SQLite Manager - Firefox addon
Eclipse 3.7
In the command prompt execute the following command to generate Maven compatible Java project named as 'HibernateSearchHelloWorld'.
1
|
mvn archetype:generate -DgroupId=com.srccodes.example.hibernate -DartifactId=HibernateSearchHelloWorld -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
|
Add dependency of Hibernate core and SQLite jdbc library. Also update 'maven-compiler-plugin' so that it uses compilation level 1.5 onwards. Otherwise annotation (introduced in JDK 5) will not work.
File : pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
<projectxmlns=" http://maven.apache.org/POM/4.0.0"xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=" http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.srccodes.example.hibernate</groupId>
<artifactId>HibernateSearchHelloWorld</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>HibernateSearchHelloWorld</name>
<url> http://maven.apache.org</url>
<dependencies>
<!-- hibernate -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.1.4.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-search</artifactId>
<version>4.1.1.Final</version>
</dependency>
<!-- SQLite JDBC library -->
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.7.2</version>
</dependency>
<!-- junit test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
|
Open the directory 'HibernateSearchHelloWorld' in command prompt and run the following maven command.
1
|
mvn eclipse:eclipse
|
On completion of the above command, Maven Java project will be converted to a Eclipse compatible java project.
Eclipse compatible Java Project structure
Open Eclipse IDE and select from the menu File --> Import --> General --> Existing Projects into Workspace
Browse to the directory of the newly converted Eclipse compatible Java Project and click 'Finish' button.
Screenshot of Eclipse project structure
Right click on 'main' and select from context menu 'New' --> 'Folder'.
Enter 'resources' in the 'Folder name' field and click the 'Finish' button.
Copy the 'hibernate.cfg.xml' file in the 'resources' folder.
File: hibernate.cfg.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
" http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<propertyname="show_sql">false</property>
<propertyname="format_sql">true</property>
<propertyname="dialect">org.hibernate.dialect.SQLiteDialect</property>
<propertyname="connection.driver_class">org.sqlite.JDBC</property>
<propertyname="connection.url">jdbc:sqlite:mydb.db</property>
<propertyname="connection.username"></property>
<propertyname="connection.password"></property>
<propertyname="hibernate.hbm2ddl.auto">update</property>
<propertyname="hibernate.search.default.directory_provider">filesystem</property>
<propertyname="hibernate.search.default.indexBase">C:\lucene\indexes</property>
<mappingclass="com.srccodes.example.hibernate.Contact"/>
</session-factory>
</hibernate-configuration>
|
Right click on 'HibernateSearchHelloWorld' project and select from context menu 'Properties' --> 'Java Build Path'.
Add 'resources' folder as shown in the screenshot below
Copy from attached source code or download SQLiteDialect and add under package 'org.hibernate.dialect' in your project.
Create a class 'Contact' under the package 'com.srccodes.example.hibernate' and copy the following content.
File: Contact.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
packagecom.srccodes.example.hibernate;
importjavax.persistence.Entity;
importjavax.persistence.Id;
importjavax.persistence.Table;
importorg.hibernate.search.annotations.Analyze;
importorg.hibernate.search.annotations.Field;
importorg.hibernate.search.annotations.Index;
importorg.hibernate.search.annotations.Indexed;
importorg.hibernate.search.annotations.Store;
/**
* The persistent class for the contact database table.
*
*/
@Entity
@Indexed
@Table(name ="contact")
publicclassContact {
privateInteger id;
privateString name;
privateString email;
publicContact() {
}
publicContact(Integer id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
@Id
publicInteger getId() {
returnthis.id;
}
publicvoidsetId(Integer id) {
this.id = id;
}
@Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO)
publicString getName() {
returnthis.name;
}
publicvoidsetName(String name) {
this.name = name;
}
publicString getEmail() {
returnemail;
}
publicvoidsetEmail(String email) {
this.email = email;
}
@Override
publicString toString() {
StringBuilder stringBuilder =newStringBuilder("Id: ").append(this.getId()).append(" | Name:").append(this.getName()).append(" | Email:").append(this.getEmail());
returnstringBuilder.toString();
}
}
|
To know basic hibernate annotation follow the tutorial Hibernate Hello World example using Maven build tool and SQLite database
@Indexed annotation specifies an entity as indexable.
@Field annotation specifies an field as searchable. Here Index.YES means 'name' field will indexed, Analyze.YES means that filed will be analyzed (excludes common stop words like 'a', 'an', 'and', 'the' etc) using default Lucene Analyzer, Store.NO means actual 'name' field data will not be stored in the index.
I have also written 'toString()' method which we'll use to print out domain objects in console.
Copy the following code to 'HibernateUtil' class of package 'com.srccodes.example.hibernate'.
File: HibernateUtil.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
packagecom.srccodes.example.hibernate;
importjava.util.Properties;
importorg.hibernate.HibernateException;
importorg.hibernate.Session;
importorg.hibernate.SessionFactory;
importorg.hibernate.cfg.Configuration;
importorg.hibernate.service.ServiceRegistry;
importorg.hibernate.service.ServiceRegistryBuilder;
/**
* Contains utility methods
*
* @author srccodes.com
* @version 1.0
*
*/
publicclassHibernateUtil {
privatestaticSessionFactory sessionFactory =null;
privatestaticServiceRegistry serviceRegistry =null;
privatestaticSessionFactory configureSessionFactory()throwsHibernateException {
Configuration configuration =newConfiguration();
configuration.configure();
Properties properties = configuration.getProperties();
serviceRegistry =newServiceRegistryBuilder().applySettings(properties).buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
returnsessionFactory;
}
// We need to configure session factory once.
// Rest of the time we will get session using the same.
static{
configureSessionFactory();
}
privateHibernateUtil() {}
publicstaticSession getSession() {
returnsessionFactory.openSession();
}
}
|
Copy the following code to 'App' class of package 'com.srccodes.example.hibernate'.
File: App.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
packagecom.srccodes.example.hibernate;
importjava.util.List;
importjava.util.Scanner;
importorg.hibernate.Session;
importorg.hibernate.search.FullTextSession;
importorg.hibernate.search.Search;
importorg.hibernate.search.query.dsl.QueryBuilder;
/**
* Hello world!
*
*/
publicclassApp {
privatestaticvoiddoIndex()throwsInterruptedException {
Session session = HibernateUtil.getSession();
FullTextSession fullTextSession = Search.getFullTextSession(session);
fullTextSession.createIndexer().startAndWait();
fullTextSession.close();
}
privatestaticList<Contact> search(String queryString) {
Session session = HibernateUtil.getSession();
FullTextSession fullTextSession = Search.getFullTextSession(session);
QueryBuilder queryBuilder = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(Contact.class).get();
org.apache.lucene.search.Query luceneQuery = queryBuilder.keyword().onFields("name").matching(queryString).createQuery();
// wrap Lucene query in a javax.persistence.Query
org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery(luceneQuery, Contact.class);
List<Contact> contactList = fullTextQuery.list();
fullTextSession.close();
returncontactList;
}
privatestaticvoiddisplayContactTableData() {
Session session =null;
try{
session = HibernateUtil.getSession();
// Fetching saved data
List<Contact> contactList = session.createQuery("from Contact").list();
for(Contact contact : contactList) {
System.out.println(contact);
}
}catch(Exception ex) {
ex.printStackTrace();
}finally{
if(session !=null) {
session.close();
}
}
}
publicstaticvoidmain(String[] args)throwsInterruptedException {
System.out.println("\n\n******Data stored in Contact table******\n");
displayContactTableData();
// Create an initial Lucene index for the data already present in the database
doIndex();
Scanner scanner =newScanner(System.in);
String consoleInput =null;
while(true) {
// Prompt the user to enter query string
System.out.print("\n\nEnter search key (To exit type 'X')");
consoleInput = scanner.nextLine();
if("X".equalsIgnoreCase(consoleInput)) {
System.out.println("End");
System.exit(0);
}
List<Contact> result = search(consoleInput);
System.out.println("\n\n>>>>>>Record found for '"+ consoleInput +"'");
for(Contact contact : result) {
System.out.println(contact);
}
}
}
}
|
After doing all the changes the overall project structure will look like this
Browse the 'mydb.db' SQLite database file (under 'HibernateSearchHelloWorld' project) using 'SQLite Manager - Firefox addon'. Populate the 'Contact' table with some dummy test data.
Screenshot of the table using 'SQLite Manager - Firefox addon' UI
Right click on 'App.java' and select from context menu 'Run As' --> 'Java Application'.
In the console, all the records of the 'Contact' table will be printed first. Then you will be prompted to enter search key. Based on the search key Hibernate Search API will return all the matching domain objects which will be printed in the console. To exit from the command prompt you have to type 'X'.
Console
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
Id: 1 | Name:Abhijit Ghosh | Email:[email protected]
Id: 3 | Name:My Name | Email:[email protected]
Id: 5 | Name:Li Chao | Email:[email protected]
Id: 6 | Name:Tom Li | Email:[email protected]
Id: 24 | Name:Your Name | Email:[email protected]
Jul 26, 2012 5:41:32 PM org.hibernate.search.impl.SimpleIndexingProgressMonitor addToTotalCount
INFO: HSEARCH000027: Going to reindex 5 entities
Jul 26, 2012 5:41:32 PM org.hibernate.search.impl.SimpleIndexingProgressMonitor indexingCompleted
INFO: HSEARCH000028: Reindexed 5 entities
Enter search key (Toexittype'X')name
>>>>>>Record foundfor'name'
Id: 3 | Name:My Name | Email:[email protected]
Id: 24 | Name:Your Name | Email:[email protected]
Enter search key (Toexittype'X')Li
>>>>>>Record foundfor'Li'
Id: 5 | Name:Li Chao | Email:[email protected]
Id: 6 | Name:Tom Li | Email:[email protected]
Enter search key (Toexittype'X')test
>>>>>>Record foundfor'test'
Enter search key (Toexittype'X')x
End
|