使用Compass实现搜索功能

1前言

Compass 是一个功能强大、支持事务的JAVA搜索引擎框架。Compass允许将对象域模型映射到搜索引擎,并能同步搜索引擎索引和数据源。Compass 在低级别的 Lucene API的基础上提供了更高级别的抽象。同时Compass实现了快速索引操作和优化,并使搜索引擎具有事务处理能力。

本文档介绍在SSH(struts+spring+hibernate)环境下配置和使用Compass的方法。
2 下载compass包

创建JAVA web工程,并导入struts、spring、hibernate所需的JAR文件及配置文件。

从官方网站http://www.compass-project.org下载Compass软件包:compass-2.2.0-with-dependencies.zip。解开压缩文件后,将compass-2.2.0.jar和lucene-core-2.4.1.jar添加到项目的Build Path中。
3 OSEM - Object/Search Engine Mapping

Compass 通过使用Java 5 注解或者简单的XML映射文件将Java对象映射到搜索引擎。

这种技术就是OSEM (Object Search Engine Mapping)。Compass 使用OSEM从对象中抽取需要的属性,并将需要的元数据插入到搜索引擎索引中。本文采用XML文件来描述对象和搜索引擎的关系。

1.   域模型的POJO

下面是一个Java POLO类。
public class Book implements java.io.Serializable {

    // Fields

    private long bookId;

    private String bookName;

    private String isbn;

    private String publisher;

    private String author;

    private long currentStock;

    private long safeStock;

    private Double price;

    private String memo;

    // 方法略

}


2.   OSEM XML映射定义

Book.cpm.xml文件的内容:
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE compass-core-mapping PUBLIC

    "-//Compass/Compass Core Mapping DTD 2.2//EN"    "http://www.compass-project.org/dtd/compass-core-mapping-2.2.dtd">

<compass-core-mapping package="cn.ittrain.tcrm.domain">

<class name="Book" alias="${mybooks.book}">

   <id name="bookId" />

   <property name="bookName">

    <meta-data>${mybooks.bookName}</meta-data>

   </property>

   <property name="isbn">

    <meta-data>${mybooks.isbn}</meta-data>

   </property>

   <property name="publisher">

    <meta-data>${mybooks.publisher}</meta-data>

   </property>

   <property name="author">

    <meta-data>${mybooks.author}</meta-data>

   </property>

   <property name="currentStock">

    <meta-data>${mybooks.currentStock}</meta-data>

   </property>

   <property name="safeStock">

    <meta-data>${mybooks.safeStock}</meta-data>

   </property>

   <property name="price">

    <meta-data>${mybooks.price}</meta-data>

   </property>

   <property name="memo">

    <meta-data>${mybooks.memo}</meta-data>

   </property>

</class>

</compass-core-mapping>

其中的元数据名和别名在下面的元数据文件中定义,Compass会自动用元数据名和别名的值来替换${}。

3.   元数据(Meta data)定义

公共元数据文件定义在OSEM映射文件中使用的元数据名和别名。

每一个类的映射定义都在一个别名下注册。别名是类的OSEM定义和类本身之间的桥梁。可以使用别名来引用一个类的映射定义。

元数据把映射定义中属性的值按照名称保存到索引中。

Book.cmd.xml文件的内容:
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE compass-core-meta-data PUBLIC

    "-//Compass/Compass Core Meta Data DTD 2.2//EN"

    "http://www.compass-project.org/dtd/compass-core-meta-data-2.2.dtd">

<compass-core-meta-data>

<meta-data-group id="mybooks" displayName="Mybooks Meta Data">

   <description>Book Meta Data</description>

   <uri>http://compass/mybooks</uri>

   <alias id="book" displayName="Book">

    <description>Book alias</description>

    <uri>http://compass/mybooks/Book</uri>

    <name>book</name>

   </alias>  

   <meta-data id="bookId" displayName="BookId">

    <description>BookId alias</description>

    <uri>http://compass/mybooks/bookId</uri>

    <name>bookId</name>

   </meta-data>

   <meta-data id="bookName" displayName="BookName">

    <description>BookName alias</description>

    <uri>http://compass/mybooks/bookName</uri>

    <name>bookName</name>

   </meta-data>

   <meta-data id="isbn" displayName="isbn">

    <description>isbn alias</description>

    <uri>http://compass/mybooks/isbn</uri>

    <name>isbn</name>

   </meta-data>

    <meta-data id="publisher" displayName="Publisher">

    <description>Publisher alias</description>

    <uri>http://compass/mybooks/publisher</uri>

    <name>publisher</name>

   </meta-data>

   <meta-data id="author" displayName="Author">

    <description>Author alias</description>

    <uri>http://compass/mybooks/author</uri>

    <name>author</name>

   </meta-data>

   <meta-data id="currentStock" displayName="CurrentStock">

    <description>CurrentStock alias</description>

    <uri>http://compass/mybooks/currentStock</uri>

    <name>currentStock</name>

   </meta-data>

   <meta-data id="safeStock" displayName="SafeStock">

    <description>SafeStock alias</description>

    <uri>http://compass/mybooks/safeStock</uri>

    <name>safeStock</name>

   </meta-data>

   <meta-data id="price" displayName="Price">

    <description>Price alias</description>

    <uri>http://compass/mybooks/price</uri>

    <name>price</name>

   </meta-data>

   <meta-data id="memo" displayName="Memo">

    <description>Memo alias</description>

    <uri>http://compass/mybooks/memo</uri>

    <name>memo</name>

   </meta-data>

</meta-data-group>

</compass-core-meta-data>


4 Hibernate配置

对3.1节中Book配置Hibernate的映射文件:Book.hbm.xml。
<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

    <class name="cn.ittrain.tcrm.domain.Book" table="BOOK" schema="LIXIANZHU">

        <id name="bookId" type="long">

            <column name="BOOK_ID" precision="22" scale="0" />

            <generator class="sequence" />

        </id>

        <property name="bookName" type="java.lang.String">

            <column name="BOOK_NAME" length="50" />

        </property>

        <property name="isbn" type="java.lang.String">

            <column name="ISBN" length="20" />

        </property>

        <property name="publisher" type="java.lang.String">

            <column name="PUBLISHER" length="50" />

        </property>

        <property name="author" type="java.lang.String">

            <column name="AUTHOR" length="20" />

        </property>

        <property name="currentStock" type="long">

            <column name="CURRENT_STOCK" precision="22" scale="0" />

        </property>

        <property name="safeStock" type="long">

            <column name="SAFE_STOCK" precision="22" scale="0" />

        </property>

        <property name="price" type="java.lang.Double">

            <column name="PRICE" precision="126" scale="0" />

        </property>

        <property name="memo" type="java.lang.String">

            <column name="MEMO" />

        </property>      

    </class>

</hibernate-mapping>


5 Spring配置

1.       在配置Compass 相关的bean之前,必须先配置SessionFactory和TransactionManager:
<bean id="sessionFactory"

         class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

         <property name="configLocation"

             value="classpath:hibernate.cfg.xml">

         </property>

</bean> 

<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">

         <property name="sessionFactory" ref="sessionFactory"/>

    </bean>

 


2.   配置Compass。Compass用来实现搜索功能。

<bean id="compass" class="org.compass.spring.LocalCompassBean">

    <property name="resourceLocations">

         <list>

             <value>classpath:Book.cmd.xml</value>

             <value>classpath:Book.cpm.xml</value>

         </list>

         </property>

    <property name="compassSettings">

         <props>

             <!-- 索引文件在服务器上的存储路径 -->

             <prop key="compass.engine.connection">target/index</prop>

         <prop key="compass.transaction.factory">org.compass.spring.transaction.SpringSyncTransactionFactory</prop>

             </props>

         </property>

         <property name="transactionManager" ref="txManager"/>

    </bean> 



3.   配置CompassGps。CompassGps用来实现索引功能。
 <!-- 与hibernate的绑定,用Hibernate 3 事件系统,支持Real Time Data Mirroring .

    经Hiberante的数据改变会自动被反射到索引里面.  -->

<bean id="hibernateGpsDevice" class="org.compass.spring.device.hibernate.dep.SpringHibernate3GpsDevice">

      <property name="name">

         <value>hibernateDevice</value>

      </property>

      <property name="sessionFactory" ref="sessionFactory"/>

    </bean> 

        

<bean id="compassGps" class="org.compass.gps.impl.SingleCompassGps" init-method="start" destroy-method="stop">

      <property name="compass" ref="compass"/>

      <property name="gpsDevices">

      <list>

         <ref local="hibernateGpsDevice"/>

      </list>

      </property>

     </bean>


4.   配置CompassSearchCommand和CompassSearchHelper。CompassSearchCommand存储搜索命令,CompassSearchHelper执行搜索查询。

<bean id="compassSearchCommand" class="org.compass.core.support.search.CompassSearchCommand"/>

   

<bean id="compassSearchHelper" class="org.compass.core.support.search.CompassSearchHelper">

         <constructor-arg value="2" /> <!-- 每页的条数 -->

         <constructor-arg ref="compass" />

</bean>


6 配置Action

SearchAction用来建立索引和搜索。indexControl方法建立索引,而searchControl方法执行搜索。SearchAction以及compassGps、compassSearchCommand、compassSearchHelper由Spring依赖注入,其在Spring配置文件中的声明不在此赘述。

public class SearchAction extends DispatchAction {

    private static final Log log = LogFactory.getLog(SearchAction.class);

    private CompassGps compassGps;

    private CompassSearchCommand compassSearchCommand;  

    private CompassSearchHelper compassSearchHelper;

    // Setter 方法略

 

    public ActionForward indexControl(ActionMapping mapping, ActionForm form,

             HttpServletRequest request, HttpServletResponse response) {

         compassGps.start();

         compassGps.index();

         return null;

    }

   

    public ActionForward searchControl(ActionMapping mapping, ActionForm form,

             HttpServletRequest request, HttpServletResponse response) {

         String query = request.getParameter("query");       

         String page = request.getParameter("page");

         Integer pageFrom = (page == null || page.length() == 0) ? 0:Integer.valueOf(page);

         compassSearchCommand.setQuery(query);

         compassSearchCommand.setPage(pageFrom);

         CompassSearchResults searchResults

= compassSearchHelper.search(compassSearchCommand);

         String commandQuery = compassSearchCommand.getQuery();

         request.setAttribute("status", commandQuery);

         request.setAttribute("searchResults", searchResults);

         return mapping.findForward("searchResults");

    }

}


7 搜索页面
<body>

  <FORM method="GET" action="search.do">

    <INPUT type="text" size="20" name="query" value="<c:out value="${status}"/>" />

    <input type="hidden" name="method" value="searchControl"/>

   <INPUT type = "submit" value="Search"/>

  </FORM> 

<c:if test="${! empty searchResults}"> 

  搜索花费 <c:out value="${searchResults.searchTime}" />毫秒

  搜索关键字:<c:out value="${status}"/>

  <c:forEach var="hit" items="${searchResults.hits}">

   <c:choose>

     <c:when test="${hit.alias == 'book'}">

       <P>

         BookId:<a href="<c:url value="/editPet.htm?petId=${hit.data.bookId}"/>">

           ${hit.data.bookId}

         </a>

         BookName:<c:out value="${hit.data.bookName}" />

         Publisher:<c:out value="${hit.data.publisher}" />

         ISBN:<c:out value="${hit.data.isbn}" />

        <br/>       

     </c:when>

   </c:choose>

  </c:forEach>

 

  <c:if test="${! empty searchResults.pages}">

    <BR><BR><BR>

    <table><tr>

    <c:forEach var="page" items="${searchResults.pages}" varStatus="pagesStatus">

      <td>

      <c:choose>

        <c:when test="${page.selected}">

          <c:out value="${page.from}" />-<c:out value="${page.to}" />

        </c:when>

        <c:otherwise>

         <FORM method="GET" action="search.do">          

    <INPUT type="hidden" name="query" value="<c:out value="${status}"/>" />

    <INPUT type="hidden" name="page" value="<c:out value="${pagesStatus.index}"/>" />          

         <input type="hidden" name="method" value="searchControl"/>

           <INPUT type = "submit" value="<c:out value="${page.from}" />-<c:out value="${page.to}" />"/>

          </FORM>

        </c:otherwise>

      </c:choose>

      </td>

    </c:forEach>

    </tr></table>

  </c:if>

</c:if>

  </body>

猜你喜欢

转载自junshang.iteye.com/blog/1750445