前几天看到Hibernate与Lucene的整合框架Hiberate Search3.0.0.GA版出来了,昨天试这写了一个Demo,感觉用起来的确很方便的,贴出来与大家分享一下。
1、创建POJO
package
com.yehui;
import
javax.persistence.CascadeType;
import
javax.persistence.Column;
import
javax.persistence.Entity;
import
javax.persistence.GeneratedValue;
import
javax.persistence.GenerationType;
import
javax.persistence.Id;
import
javax.persistence.JoinColumn;
import
javax.persistence.ManyToOne;
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.IndexedEmbedded;
import
org.hibernate.search.annotations.Store;
/** */
/** * Employee generated by MyEclipse Persistence Tools */
@Entity@Table(name
=
"
employee
"
, catalog
=
"
hise
"
, uniqueConstraints
=
...
{}
)@Indexed(index
=
"
indexes/employee
"
)
public
class
Employee
implements
java.io.Serializable
...
{ private static final long serialVersionUID = 7794235365739814541L; private Integer empId; private String empName; private Department dept; private String empNo; private Double empSalary; // Constructors /** *//** default constructor */ public Employee() ...{ } /** *//** minimal constructor */ public Employee(Integer empId) ...{ this.empId = empId; } /** *//** full constructor */ public Employee(Integer empId, String empName, String empNo, Double empSalary) ...{ this.empId = empId; this.empName = empName; this.empNo = empNo; this.empSalary = empSalary; } // Property accessors @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "emp_id", unique = true, nullable = false, insertable = true, updatable = true) @DocumentId public Integer getEmpId() ...{ return this.empId; } public void setEmpId(Integer empId) ...{ this.empId = empId; } @Column(name = "emp_name", unique = false, nullable = true, insertable = true, updatable = true, length = 30) @Field(name="name", index=Index.TOKENIZED, store=Store.YES) public String getEmpName() ...{ return this.empName; } public void setEmpName(String empName) ...{ this.empName = empName; } @Column(name = "emp_no", unique = false, nullable = true, insertable = true, updatable = true, length = 30) @Field(index=Index.UN_TOKENIZED) public String getEmpNo() ...{ return this.empNo; } public void setEmpNo(String empNo) ...{ this.empNo = empNo; } @Column(name = "emp_salary", unique = false, nullable = true, insertable = true, updatable = true, precision = 7) public Double getEmpSalary() ...{ return this.empSalary; } public void setEmpSalary(Double empSalary) ...{ this.empSalary = empSalary; } @ManyToOne(cascade = CascadeType.ALL) @JoinColumn(name="dept_id") @IndexedEmbedded(prefix="dept_", depth=1) public Department getDept() ...{ return dept; } public void setDept(Department dept) ...{ this.dept = dept; }}
package
com.yehui;
import
java.util.List;
import
javax.persistence.Column;
import
javax.persistence.Entity;
import
javax.persistence.GeneratedValue;
import
javax.persistence.GenerationType;
import
javax.persistence.Id;
import
javax.persistence.OneToMany;
import
javax.persistence.Table;
import
org.hibernate.search.annotations.ContainedIn;
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;
/** */
/** * Department generated by MyEclipse Persistence Tools */
@Entity@Table(name
=
"
department
"
, catalog
=
"
hise
"
, uniqueConstraints
=
...
{}
)@Indexed(index
=
"
indexes/department
"
)
public
class
Department
implements
java.io.Serializable
...
{ private static final long serialVersionUID = 7891065193118612907L; private Integer deptId; private String deptNo; private String deptName; private List<Employee> empList; // Constructors @OneToMany(mappedBy="dept") @ContainedIn public List<Employee> getEmpList() ...{ return empList; } public void setEmpList(List<Employee> empList) ...{ this.empList = empList; } /** *//** default constructor */ public Department() ...{ } /** *//** minimal constructor */ public Department(Integer deptId) ...{ this.deptId = deptId; } /** *//** full constructor */ public Department(Integer deptId, String deptNo, String deptName) ...{ this.deptId = deptId; this.deptNo = deptNo; this.deptName = deptName; } // Property accessors @Id @GeneratedValue(strategy=GenerationType.AUTO) @Column(name = "dept_id", unique = true, nullable = false, insertable = true, updatable = true) @DocumentId public Integer getDeptId() ...{ return this.deptId; } public void setDeptId(Integer deptId) ...{ this.deptId = deptId; } @Column(name = "dept_no", unique = false, nullable = true, insertable = true, updatable = true, length = 30) public String getDeptNo() ...{ return this.deptNo; } public void setDeptNo(String deptNo) ...{ this.deptNo = deptNo; } @Column(name = "dept_name", unique = false, nullable = true, insertable = true, updatable = true, length = 30) @Field(name="name", index=Index.TOKENIZED,store=Store.YES) public String getDeptName() ...{ return this.deptName; } public void setDeptName(String deptName) ...{ this.deptName = deptName; }}
不了解Hibernate映射相关的Annotation的朋友可以到Hibernate的官方网站下载Hibernate Annotation Reference,有http://wiki.redsaga.com/翻译的中文文档。当然,也可以直接使用hbm.xml文件。
Hibernate Search相关的Annotation主要有两个:
@Indexed 标识需要进行索引的对象,
属性 index 指定索引文件的路径
@Field 标注在类的get属性上,标识一个索引的Field
属性 index 指定是否索引,与Lucene相同
store 指定是否索引,与Lucene相同
name 指定Field的name,默认为类属性的名称
analyzer 指定分析器
另外@IndexedEmbedded 与 @ContainedIn 用于关联类之间的索引
@IndexedEmbedded有两个属性,一个prefix指定关联的前缀,一个depth指定关联的深度
如上面两个类中Department类可以通过部门名称name来索引部门,在Employee与部门关联的前缀为dept_,因此可以通过部门名称dept_name来索引一个部门里的所有员工。
2、配置文件
<?
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
="hibernate.dialect"
>
org.hibernate.dialect.MySQLDialect
</
property
>
<
property
name
="hibernate.connection.url"
>
jdbc:mysql://localhost:3306/hise
</
property
>
<
property
name
="hibernate.connection.username"
>
root
</
property
>
<
property
name
="hibernate.connection.password"
>
123456
</
property
>
<
property
name
="hibernate.connection.driver_class"
>
com.mysql.jdbc.Driver
</
property
>
<
property
name
="hibernate.search.default.directory_provider"
>
org.hibernate.search.store.FSDirectoryProvider
</
property
>
<
property
name
="hibernate.search.default.indexBase"
>
e:/index
</
property
>
<
mapping
class
="com.yehui.Employee"
/>
<
mapping
class
="com.yehui.Department"
/>
</
session-factory
>
</
hibernate-configuration
>
如果使用JPA,配置文件为
<?
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
="jpaPU"
transaction-type
="RESOURCE_LOCAL"
>
<
provider
>
org.hibernate.ejb.HibernatePersistence
</
provider
>
<
class
>
com.yehui.Department
</
class
>
<
class
>
com.yehui.Employee
</
class
>
<
properties
>
<
property
name
="hibernate.connection.driver_class"
value
="com.mysql.jdbc.Driver"
/>
<
property
name
="hibernate.connection.url"
value
="jdbc:mysql://localhost:3306/hise"
/>
<
property
name
="hibernate.connection.username"
value
="root"
/>
<
property
name
="hibernate.connection.password"
value
="123456"
/>
<
property
name
="hibernate.search.default.directory_provider"
value
="org.hibernate.search.store.FSDirectoryProvider"
/>
<
property
name
="hibernate.search.default.indexBase"
value
="e:/index"
/>
</
properties
>
</
persistence-unit
>
</
persistence
>
主要就是添加两个属性,
hibernate.search.default.directory_provider指定Directory的代理,即把索引的文件保存在硬盘中(
org.hibernate.search.store.FSDirectoryProvider)还是内存里(
org.hibernate.search.store.RAMDirectoryProvider),保存在硬盘的话
hibernate.search.default.indexBase属性指定索引保存的路径。3、测试代码
package
com.yehui;
import
static
junit.framework.Assert.assertNotNull;
import
static
junit.framework.Assert.assertTrue;
import
java.util.List;
import
org.apache.lucene.analysis.StopAnalyzer;
import
org.apache.lucene.queryParser.QueryParser;
import
org.hibernate.Query;
import
org.hibernate.Session;
import
org.hibernate.SessionFactory;
import
org.hibernate.Transaction;
import
org.hibernate.cfg.AnnotationConfiguration;
import
org.hibernate.search.FullTextSession;
import
org.hibernate.search.Search;
import
org.junit.After;
import
org.junit.Before;
import
org.junit.BeforeClass;
import
org.junit.Test;
public
class
SearchResultsHibernate
...
{ private static SessionFactory sf = null; private static Session session = null; private static Transaction tx = null; @BeforeClass public static void setupBeforeClass() throws Exception ...{ sf = new AnnotationConfiguration().configure("hibernate.cfg.xml").buildSessionFactory(); assertNotNull(sf); } @Before public void setUp() throws Exception ...{ session = sf.openSession(); tx = session.beginTransaction(); tx.begin(); } @After public void tearDown() throws Exception ...{ tx.commit(); session.close(); } public static void tearDownAfterClass() throws Exception ...{ if (sf != null) sf.close(); } @Test public void testAddDept() throws Exception ...{ Department dept = new Department(); dept.setDeptName("Market"); dept.setDeptNo("6000"); Employee emp = new Employee(); emp.setDept(dept); emp.setEmpName("Kevin"); emp.setEmpNo("KGP1213"); emp.setEmpSalary(8000d); session.save(emp); } @Test public void testFindAll() throws Exception ...{ Query query = session.createQuery("from Department"); List<Department> deptList = query.list(); assertTrue(deptList.size() > 0); } @Test public void testIndex() throws Exception ...{ FullTextSession fullTextSession = Search.createFullTextSession(session); assertNotNull(session); QueryParser parser = new QueryParser("name", new StopAnalyzer()); org.apache.lucene.search.Query luceneQuery = parser .parse("name:Kevin"); Query hibQuery = fullTextSession.createFullTextQuery(luceneQuery, Employee.class); List list = hibQuery.list(); assertTrue(list.size() > 0); } @Test public void testIndex2() throws Exception ...{ FullTextSession fullTextSession = Search.createFullTextSession(session); assertNotNull(session); QueryParser parser = new QueryParser("dept_name", new StopAnalyzer()); org.apache.lucene.search.Query luceneQuery = parser .parse("dept_name:Market"); Query hibQuery = fullTextSession.createFullTextQuery(luceneQuery, Employee.class); List list = hibQuery.list(); assertTrue(list.size() > 0); }}
测试通过。OK