Chapter 24. Hibernate Search

24.1. 简介

如Apache Lucene™ 之类的全文搜索引擎是一种非常强大的技术,给我们的应用程序带来了高效的文本查询。 在处理一个对象域模型的时候有可能会遇到多处不匹配(保持最新的索引,索引结构和域模型之间的不匹配,查询不匹配...) Hibernate Search根据一些注解来索引域模型、管理数据库与索引的同步,并从自由文本查询中带给你正常的受管对象。 Hiberante Search在目前的版本里使用了Apache Luncene。

Hibernate Search在设计之初就是要很好并且尽可能自然地集成JPA和Hibernate,因此自然而然的,JBoss Seam也就提供了Hibernate Search的集成。

请参考Hibernate Search项目文档信息 Hibernate Search documentation

24.2. 配置

Hibernate Search既可以在 META-INF/persistence.xml 中也可以在 hibernate.cfg.xml 中进行配置。

对大多数配置参数来说,Hibernate Search配置为其提供合理的默认值,在这里有一个最小化配置的描述。

   <persistence-unit name="sample">
      <jta-data-source>java:/DefaultDS</jta-data-source>
      <properties>
         [...]
         <!-- use a file system based index -->
         <property name="hibernate.search.default.directory_provider" 
                   value="org.hibernate.search.store.FSDirectoryProvider"/>
         <!-- directory where the indexes will be stored -->
         <property name="hibernate.search.default.indexBase" 
                   value="/Users/prod/apps/dvdstore/dvdindexes"/>
      </properties>
   </persistence-unit>

如果计划使用Hibernate Annotations或者EntityManager 3.2.x(已经嵌入到JBoss AS 4.2.GA中),那也需要配置相应的事件监听器。

   <persistence-unit name="sample">
      <jta-data-source>java:/DefaultDS</jta-data-source>
      <properties>
         [...]
         <!-- use a file system based index -->
         <property name="hibernate.search.default.directory_provider" 
                   value="org.hibernate.search.store.FSDirectoryProvider"/>
         <!-- directory where the indexes will be stored -->
         <property name="hibernate.search.default.indexBase" 
                   value="/Users/prod/apps/dvdstore/dvdindexes"/>

         <property name="hibernate.ejb.event.post-insert" 
                   value="org.hibernate.search.event.FullTextIndexEventListener"/>
         <property name="hibernate.ejb.event.post-update" 
                   value="org.hibernate.search.event.FullTextIndexEventListener"/>
         <property name="hibernate.ejb.event.post-delete" 
                   value="org.hibernate.search.event.FullTextIndexEventListener"/>

      </properties>
   </persistence-unit>
[Note]Note

如果是使用了Hibernate Annotation或者EntityManager 3.3.x,这一步就不再需要了。

除了配置文件之外,把下面的jars包需要部署到服务器中或者打包进入你的工程中:

  • hibernate-search.jar

  • hibernate-commons-annotations.jar

  • lucene-core.jar

[Note]Note

如果部署的是一个EAR包,别忘了要更新 application.xml 文件

24.3. 用法

Hibernate Search使用注解来映射实体类给Lucene索引,访问 reference documentation 来获取更多的说明。

Hibernate Search完全集成JPA/Hibernate的API和语法。只需要几行代码,就可以在基于HQL或者Criteria的查询间进行切换。主API和应用程序是通过 FullTextSession API (Hibernate Session 的子类)相互交互的。

当有Hibernate Search的时候,JBoss Seam注入 FullTextSession

@Stateful
@Name("search")
public class FullTextSearchAction implements FullTextSearch, Serializable
{   
   @In
   FullTextSession session;

   public void search(String searchString) {
      org.apache.lucene.query.Query luceneQuery = getLuceneQuery();
      org.hibernate.Query query session.createFullTextQuery(luceneQuery, Product.class);
      searchResults = query
            .setMaxResults(pageSize + 1)
            .setFirstResult(pageSize * currentPage)
            .list();
   }
   [...]
}  

[Note]Note

FullTextSession 继承自 org.hibernate.Session,因此它可以被当作正常的Hibernate Session来使用。

如果使用Java Persistence API,建议做一个平滑的集成。

@Name("search")
public class FullTextSearchAction implements FullTextSearch, Serializable
{   
   @In
   FullTextEntityManager em;

   public void search(String searchString) {
      org.apache.lucene.query.Query luceneQuery = getLuceneQuery();
      javax.persistence.Query query = em.createFullTextQuery(luceneQuery, Product.class);
      searchResults = query
            .setMaxResults(pageSize + 1)
            .setFirstResult(pageSize * currentPage)
            .getResultList();
   }
   [...]
}  

当有Hibernate Search的时候,FulltextEntityManager 被注入。 FullTextEntityManager 继承了 EntityManager 并带有特定的搜索方法, 同样 FullTextSession 继承了 Session

当注入 EJB 3.0 Session 或者 Message Driven Bean 时(例如使用 @PersistenceContext 注解的Bean), 就不可能在定义声明中使用 FullTextEntityManager 接口来替换 EntityManager 接口。 然而,将注入一个 FullTextEntityManager 实现:进行类型转换后就可以了。

@Stateful
@Name("search")
public class FullTextSearchAction implements FullTextSearch, Serializable
{   
   @PersistenceContext
   EntityManager em;

   public void search(String searchString) {
      org.apache.lucene.query.Query luceneQuery = getLuceneQuery();
      FullTextEntityManager ftEm = (FullTextEntityManager) em;
      javax.persistence.Query query = ftEm.createFullTextQuery(luceneQuery, Product.class);
      searchResults = query
            .setMaxResults(pageSize + 1)
            .setFirstResult(pageSize * currentPage)
            .getResultList();
   }
   [...]
}  

[Caution]Caution

对于那些经习惯了在Seam之外使用Hibernate Search的人来说,要注意使用 Search.createFullTextSession 是不需要的了。

对于Hibernate Search更详细的示例用法,请查看JBoss Seam发行包中的DVDStore或者Blog示例。