Jumpa lagi kita dengan team nostratech.
Kali ini kita akan belajar tentang seraching data di database
menggunakan Full Text Search. Apa itu full text search?.
Seperti saat kita search di google.
Kita ketik keyword apa, maka akan muncul list data yang sesuai (match
atau sama persis dengan keyword yang kita ketik) dan juga semua data
ada hubungannya dengan keyword yang kita ketik. Misal kita ketik
'hibernate book', maka akan muncul semua list yang ada kata mirip
denhan 'hibernate' dan 'book'.
Seperti itulah sederhananya pengertian
full text search.
Kita ambil contoh yang sederhana saja.
Misalnya kita punya data list nama
contact di tabel seperti ini :
Disini kita asumsikan kita menggunakan
ORM hibernate.
Bagaimana caranya search data “Paolo
Coelho Jr” ? Kalo menggunakan keyword 'paolo' tentunya kita memakai
query :
select a from Contact where a.name like 'paolo%'
jika keyword dari usernya 'coelho' :
select a from Contact where a.name like '%coelho%'
Nah bagaimana jika keyword dari usernya
seperti ini : 'coelho Jr', 'coelho jr paolo', 'famous writer paolo
coelho', 'the name of Coelho NM paolo ' dan lain lain.
Tentu kita akan bingung dan akan
kesulitan tentunya kita.
Search query classic : name like
'%keyword%' tentu tidak bisa menghandle lagi jika sudah menggunakan
query yang aneh aneh seperti diatas.
Selain tidak mendapatkan hasil yang
diharapkan, tentunya query %% tentu sangat buruk untuk masalah
performence kalau datanya sudah terlampau banyak (walaupun field name
di tabel Contact sudah di Index).
Solusinya kita bisa menggunakan library
hibernate-search untuk menangani search query untuk problem diatas.
Hibernate search didalamnya menggunakan
engine apache lucene untuk indexing datanya. Jadi nantinya data Name
dari tabel Contact akan disimpan di index lucene.
Hibernate tidak akan langsung mencari
data di tabel contact tetapi di cari terlebih dulu di index luncene.
Hibernate config xml
Hibernate session until (kalau kita mengunakan JPA diatas hibernate kita bisa menggunakan entity manager)
Create indexing pada setiap insert, update, delete data agar index di lucene terupdate mengikuti data di tabel.
Setiap kata di property Contact -> name di index oleh lucene (dan disimpan Id nya). Dari sinilah hibernate mencari index beradasarkan keyword yang diinginkan
Proses yang terjadi kurang lebih
seperti ini :
Hibernate --> search index lucene -->
search index name dan get id nya --> search ke tabel contact
berdasarkan id --> tampilkan data.
Tambahkan dependency maven di pom.xml
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.3.9.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-search-orm</artifactId>
<version>5.2.0.Final</version>
</dependency>
Mari kita mulai ke contohnya.
Kita buat dulu model Contact.
Set property mana yang akan diindex
menggunakan @Field
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.apache.lucene.analysis.core.LowerCaseFilterFactory;
import org.apache.lucene.analysis.snowball.SnowballPorterFilterFactory;
import org.apache.lucene.analysis.standard.StandardTokenizerFactory;
import org.hibernate.search.annotations.*;
/**
* The persistent class for the contact database table.
*/
@Entity
@Indexed
@AnalyzerDef(name = "customanalyzer",
tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),
filters = {
@TokenFilterDef(factory = LowerCaseFilterFactory.class)
, @TokenFilterDef(factory = SnowballPorterFilterFactory.class
)
})
@Table(name = "contact")
public class Contact {
@Id
@DocumentId
private Integer id;
@Field(index = Index.YES, store = Store.NO)
@Analyzer(definition = "customanalyzer")
private String name;
private String email;
/// setter + getter
}
Hibernate config xml
<?xml version="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>
<property name="show_sql">false</property>
<property name="format_sql">true</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/test</property>
<property name="connection.username">root</property>
<property name="connection.password"></property>
<property name="hibernate.hbm2ddl.auto">update</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.search.default.directory_provider">filesystem</property>
<property name="hibernate.search.default.indexBase">/tmp/lucene/indexes</property>
<mapping class="com.srccodes.example.hibernate.Contact"/>
</session-factory>
</hibernate-configuration>
untuk menentukan dimana kita menyimpan
file index nya.
<property name="hibernate.search.default.directory_provider">filesystem</property>
<property name="hibernate.search.default.indexBase">/tmp/lucene/indexes</property>
Hibernate session until (kalau kita mengunakan JPA diatas hibernate kita bisa menggunakan entity manager)
public class HibernateUtil {
private static SessionFactory sessionFactory = null;
private static ServiceRegistry serviceRegistry = null;
private static SessionFactory configureSessionFactory() throws HibernateException {
Configuration configuration = new Configuration();
configuration.configure();
Properties properties = configuration.getProperties();
serviceRegistry = new ServiceRegistryBuilder().applySettings(properties).buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
return sessionFactory;
}
static {
configureSessionFactory();
}
private HibernateUtil() {}
public static Session getSession() {
return sessionFactory.openSession();
}
}
Create indexing pada setiap insert, update, delete data agar index di lucene terupdate mengikuti data di tabel.
private void doIndex() throws InterruptedException {
Session session = HibernateUtil.getSession();
FullTextSession fullTextSession = Search.getFullTextSession(session);
fullTextSession.createIndexer().startAndWait();
fullTextSession.close();
}
Create fulltext session dan lucene
query yang nantinya akan diterjemahkan ke JPA/hibernate query. Jadi
kita tidak perlu secara detail tahu tentang lucene query karen sudah
dihandle oleh si hibernate.
private List<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();
org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery(luceneQuery, Contact.class);
List<Contact> contactList = fullTextQuery.list();
fullTextSession.close();
return contactList;
}
jika dilihat di sq log maka query
ditabel contact hanya mengunakan where id (yg didapat dari lucene
index) tidak ada pencarian berasarkan 'name'. Karena name sudah
dihandle oleh hibernate-search.
Hibernate:
select
this_.id as id1_0_0_,
this_.email as email2_0_0_,
this_.name as name3_0_0_
from
contact this_
where
(
this_.id in (
?
)
)
Berikut contoh pencarian data dengan
beberapa keyword :
>>>>>>Record found for 'paolo coelho' count : 1
Id: 2 | Name:Paolo Coelho | Email:paolo@gmail.com
===============================================
>>>>>>Record found for 'mr coelho paolo is his name' count : 1
Id: 2 | Name:Paolo Coelho | Email:paolo@gmail.com
===============================================
>>>>>>Record found for 'who is mister coelho paolo ?' count : 1
Id: 2 | Name:Paolo Coelho | Email:paolo@gmail.com
===============================================
>>>>>>Record found for 'famous writer paolo coelho' count : 1
Id: 2 | Name:Paolo Coelho | Email:paolo@gmail.com
===============================================
Sekedar tambahan file index lucene bisa
dibuka menggunakan software Luke.
Setiap kata di property Contact -> name di index oleh lucene (dan disimpan Id nya). Dari sinilah hibernate mencari index beradasarkan keyword yang diinginkan
Sample source code : https://github.com/andrisasuke/hibernate-search-sample
Happy coding & selamat menjalankan
ibadah puasa ramadhan bagi yang menjalankan.
No comments:
Post a Comment