天天看點

用compass快速給你的網站添加搜尋功能<二>

    在上一篇文章中主要講了,配置要索引的表和compass與spring整合時的配置。接下來我把餘下的兩部分寫出來。

       第三步:配置手動建立索引的功能。

       這個其實隻需在第一次生成索引的時候用,當系統正常運作時,compass中的hibernateGps會自動檢測資料的變動,同時同步索引檔案的。

      首先在applicationContext.xml中配置bean.

       <!-- 手工生成索引 -->

 <bean id="buildIndexController"

  class="org.compass.spring.web.mvc.CompassIndexController">

  <property name="compassGps" ref="hibernateGps" />

  <property name="indexView" value="/ftl/create.ftl" />

  <property name="indexResultsView" value="/ftl/create.ftl" />

 </bean>

 同時我們也要配置與之相應的請求映射。

 <bean id="urlHandlerMapping"

  class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

  <property name="mappings">

   <props>

       <prop key="/buildindex.htm">buildIndexController</prop>

      </props>

  </property>

  最後就是自動生成索引的頁面了,這裡我用的是freemarker.用什麼都一樣,你可以用jsp,html.

 create.ftl(在WebRoot下的ftl檔案夾下)

 <html>

 <head>

  <title>builderIndex</title>

 </head>

 <body>

  <h1>

   手工重建索引

  </h1>

  <p>

   <form name="keyword" action="/buildindex.htm" method="post">

   <INPUT type="hidden" name="doIndex" value="true">

   <input type="submit" value="手工重建索引" />

  </form>

  <#if indexResults?exists>

    本次索引耗時${indexResults.indexTime}毫秒!

    </#if>

    <p>

 </body>

</html>

 當我們點選手工重建索引按鈕時,會在我們指定的索引目錄下<prop key="compass.engine.connection">E:/video</prop>也就先在E:/video下生成gpsindex/video-index當索引生成完以後,會傳回生成索引所用的毫秒數。這時就會把gpsindex檔案夾下的video-index覆寫到E:/video/index/下的video-index檔案夾。這時gpsindex/video-index也消失了。這就是簡單的生成索引的過程。接下來我們要說最後一步了。索引我們已建好了,怎麼去搜尋我們想要的資料了。

   第四步:建立搜尋功能。

     首先寫一個controller.即searchController.java

public class SearchController extends AbstractCompassCommandController {

 private String searchView;

 private String searchResultsView;

 private String searchResultsName = "searchResults";

 private Integer pageSize;

 private Integer sectionSize;

 private CompassSearchHelper searchHelper;

 public CompassSearchHelper getSearchHelper() {

  return searchHelper;

 }

 public SearchController() {

  setCommandClass(CompassSearchCommand.class);

 public void afterPropertiesSet() throws Exception {

  super.afterPropertiesSet();

  if (searchView == null) {

   throw new IllegalArgumentException(

     "Must set the searchView property");

  }

  if (searchResultsView == null) {

     "Must set the serachResultsView property");

  if (searchHelper == null) {

   searchHelper = new CompassSearchHelper(getCompass(), getPageSize());

 protected ModelAndView handle(HttpServletRequest request,

   HttpServletResponse response, Object command, BindException errors)

   throws Exception {

  Log log4j = LogFactory.getLog("video");

  log4j.info("SearchController say: hello");

  final CompassSearchCommand searchCommand = (CompassSearchCommand) command;

  String query = searchCommand.getQuery();

  searchCommand.setQuery(query);

  if (!StringUtils.hasText(searchCommand.getQuery())) {

   return new ModelAndView(getSearchView(), getCommandName(),

     searchCommand);

  CompassSearchResults searchResults = searchHelper.search(searchCommand);

  log4j.info("searchResults.getHits().length = "

    + searchResults.getHits().length);

  CompassPage page = new CompassPage(searchResults.getHits(),

    pageSize.intValue(),

    searchCommand.getPage().intValue() + 1,

    searchResults.getTotalHits(),

    sectionSize.intValue(),

    searchCommand.getQuery(),

    searchResults.getSearchTime());

  return new ModelAndView(getSearchResultsView(), "data", page);

 /**

  * Returns the view that holds the screen which the user will initiate the

  * search operation.

  */

 public String getSearchView() {

  return searchView;

  * Sets the view that holds the screen which the user will initiate the

 public void setSearchView(String searchView) {

  this.searchView = searchView;

  * Returns the name of the results that the

  * saved under. Defaults to "searchResults".

 public String getSearchResultsName() {

  return searchResultsName;

  * Sets the name of the results that the

 public void setSearchResultsName(String searchResultsName) {

  this.searchResultsName = searchResultsName;

  * Returns the view which will show the results of the search operation.

 public String getSearchResultsView() {

  return searchResultsView;

  * Sets the view which will show the results of the search operation.

 public void setSearchResultsView(String resultsView) {

  this.searchResultsView = resultsView;

  * Sets the page size for the pagination of the results. If not set, not

  * pagination will be used.

 public Integer getPageSize() {

  return pageSize;

  * Returns the page size for the pagination of the results. If not set, not

  * 

  * @param pageSize

  *            The page size when using paginated results

 public void setPageSize(Integer pageSize) {

  this.pageSize = pageSize;

  * <p>

  * The search helper is used to execute teh actual search. By default (if

  * not set) the search controller will create a new search helper. If

  * provided, the search controller will use it to perform the search.

  * Mainly used to extend the search helper and execute additional operation

  * within specific calbacks the search helper exposes.

  * @param searchHelper

  *            A specific search helper to use

 public void setSearchHelper(CompassSearchHelper searchHelper) {

  this.searchHelper = searchHelper;

 public Integer getSectionSize() {

  return sectionSize;

 public void setSectionSize(Integer sectionSize) {

  this.sectionSize = sectionSize;

}

 還需要一個CompassPage.java主要來實作分頁的。

 public class CompassPage implements Page {

 private CompassHit[] elements;

 private int pageSize;

 private int pageNumber;

 private int totalElements = 0;

 private int sectionSize;

 private String query;

 private long searchTime;

 public long getSearchTime() {

  return searchTime;

 public void setSearchTime(long searchTime) {

  this.searchTime = searchTime;

  * @param pageNumber

  *            目前頁編碼,從1開始,如果傳的值為Integer.MAX_VALUE表示擷取最後一頁。

  *            如果你不知道最後一頁編碼,傳Integer.MAX_VALUE即可。如果目前頁超過總頁數,也表示最後一頁。

  *            這兩種情況将重新更改目前頁的頁碼為最後一頁編碼。

  *            每一頁顯示的條目數

  * @param sectionSize

  *            每一節顯示的頁數.

 public CompassPage(CompassHit[] elements, int pageSize, int pageNumber, int totalElements, int sectionSize, String query, long searchTime) {

  super();

  this.elements = elements;

  this.pageNumber = pageNumber;

  this.totalElements = totalElements;

  this.query = query;

  if (Integer.MAX_VALUE == this.pageNumber

    || this.pageNumber > getLastPageNumber()) // last page

  {

   this.pageNumber = getLastPageNumber();

  } 

 public String getQuery() {

  return query;

 public void setQuery(String query) {

 public CompassHit[] getElements() {

  return elements;

 public void setElements(CompassHit[] elements) {

 public int getPageNumber() {

  return pageNumber;

 public void setPageNumber(int pageNumber) {

 public int getSectionSize() {

 public void setSectionSize(int sectionSize) {

 public int getTotalElements() {

  return totalElements;

 public void setTotalElements(int totalElements) {

 public void setPageSize(int pageSize) {

 public int getLastPageNumber() {

  return totalElements % this.pageSize == 0 ? totalElements

    / this.pageSize : totalElements / this.pageSize + 1;

 public int getNextPageNumber() {

  return getThisPageNumber() + 1;

 public int getNextSectionFirstPageNumber() {

  return (pageNumber / sectionSize + 1) * sectionSize + 1;

 public int getPageSize() {

 public int getPreviousPageNumber() {

  return (getThisPageNumber() == 1) ? 1 : getThisPageNumber() - 1;

 public int getPreviousSectionFirstPageNumber() {

  return (pageNumber / sectionSize - 1) * sectionSize + 1;

 public Object getThisPageElements() {

 public int getThisPageFirstElementNumber() {

  return (getThisPageNumber() - 1) * getPageSize() + 1;

 public int getThisPageLastElementNumber() {

  int fullPage = getThisPageFirstElementNumber() + getPageSize() - 1;

  return getTotalNumberOfElements() < fullPage ? getTotalNumberOfElements()

    : fullPage;

 public int getThisPageNumber() {

 public int getThisSectionFirstPageNumber() {

  return (getThisPageNumber() % sectionSize == 0) ? getThisPageNumber()

    / sectionSize * sectionSize : getThisPageNumber() / sectionSize

    * sectionSize + 1;

 public int getThisSectionLastPageNumber() {

  int fullSection = (getThisPageNumber() / sectionSize + 1) * sectionSize;

  return getLastPageNumber() < fullSection ? getLastPageNumber()

    : fullSection;

 public List getThisSectionPagesBar() {

  // 翻頁 頁碼條

  List pagesBar = new ArrayList();

  if (hasPreviousSection()) { // 不是第一捆

   if (hasNextSection()) {// 不是最後一捆

    for (int j = getPreviousSectionFirstPageNumber() + sectionSize; j <= getNextSectionFirstPageNumber() - 1; j++) {

     pagesBar.add(new Integer(j));

    }

   } else { // 是最後一捆

    for (int j = getPreviousSectionFirstPageNumber() + sectionSize; j <= (getLastPageNumber()); j++) {

   }

  } else { // 是第一捆

   // log4j.info("是第一捆 getLastPageNumber()=" + getLastPageNumber());

   for (int j = 1; j <= (getLastPageNumber() < sectionSize ? getLastPageNumber()

     : sectionSize); j++) {

    // log4j.info("j=" + j);

    pagesBar.add(new Integer(j));

  return pagesBar;

 public int getTotalNumberOfElements() {

 public boolean hasNextPage() {

  return getLastPageNumber() > getThisPageNumber();

 public boolean hasNextSection() {

  return getLastPageNumber() > (pageNumber / sectionSize + 1)

    * sectionSize;

 public boolean hasPreviousPage() {

  return getThisPageNumber() > 1;

 public boolean hasPreviousSection() {

  return pageNumber / sectionSize * sectionSize > 1;

 public boolean isFirstPage() {

  return getThisPageNumber() == 1;

 public boolean isLastPage() {

  return getThisPageNumber() >= getLastPageNumber();

在定義一個分頁接口Page.java。

/**

 * 分頁資訊接口

 */

public interface Page

{

    /**

     * 是否是首頁(第一頁),第一頁頁碼為1

     *

     * @return 首頁辨別

     */

    public boolean isFirstPage();

     * 是否是最後一頁

     * @return 末頁辨別

    public boolean isLastPage();

     * 是否有下一頁

     * @return 下一頁辨別

    public boolean hasNextPage();

     * 是否有上一頁

     * @return 上一頁辨別

    public boolean hasPreviousPage();

      是否有下一個頁面單元

    */

    public boolean hasNextSection();

    /**是否有前一個頁面單元*/

    public boolean hasPreviousSection();

     * 擷取最後一頁頁碼,也就是總頁數

     * @return 最後一頁頁碼

    public int getLastPageNumber();

     * 目前頁包含的資料,不同的情況可能傳回的資料類型不一樣,如List,RowSet等,請參考具體的實作

     * @return 目前頁資料源

    public Object getThisPageElements();

     * 總的資料條目數量,0表示沒有資料

     * @return 總數量

    public int getTotalNumberOfElements();

     * 擷取目前頁的首條資料的行編碼

     * @return 目前頁的首條資料的行編碼

    public int getThisPageFirstElementNumber();

     * 擷取目前頁的末條資料的行編碼

     * @return 目前頁的末條資料的行編碼

    public int getThisPageLastElementNumber();

     * 擷取下一頁編碼

     * @return 下一頁編碼

    public int getNextPageNumber();

     * 擷取上一頁編碼

     * @return 上一頁編碼

    public int getPreviousPageNumber();

    /* 擷取下一個頁面單元的第一頁 */

    public int getNextSectionFirstPageNumber();

    /* 擷取前一個頁面單元的第一頁 */

    public int getPreviousSectionFirstPageNumber();

     * 每一頁顯示的條目數

     * @return 每一頁顯示的條目數

    public int getPageSize();

     * 目前頁的頁碼

     * @return 目前頁的頁碼

    public int getThisPageNumber();

    /*

     目前片斷第一頁頁碼

    public int getThisSectionFirstPageNumber();

    public int getThisSectionLastPageNumber();

   /*

    *目前片斷 頁碼表 

    public List getThisSectionPagesBar();

最後要配置一下bean和請求映射了。

<bean id="urlHandlerMapping"

     <prop key="/search.htm">searchController</prop> 

   </props>

<!-- 搜尋的控制器 -->

 <bean id="searchController"

  class="com.jack.video.SearchController" lazy-init="true">

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

  <property name="searchView" value="/ftl/search.ftl" />

  <property name="searchResultsView"

   value="/ftl/search.ftl" />

  <property name="pageSize" value="10" />

  <property name="sectionSize" value="10" />

  <property name="searchHelper">

   <ref local="advanceCompassSearchHelper" />

 最後為了能給搜尋到的結果高亮顯示。還需要配置。

<!-- 高亮字段顯示 -->

 <bean id="advanceCompassSearchHelper"

  class="com.jack.video.util.AdvanceCompassSearchHelper">

  <property name="highlightFields">

   <list>

    <value>CName</value>

   </list>

  <property name="pageSize">

   <value>10</value>

  <constructor-arg ref="compass" />

AdvanceCompassSearchHelper .java檔案

 public class AdvanceCompassSearchHelper extends CompassSearchHelper {

 private String[] highlightFields;

 public String[] getHighlightFields() {

  return highlightFields;

 public void setHighlightFields(String[] highlightFields) {

  this.highlightFields = highlightFields;

  * @param compass

 public AdvanceCompassSearchHelper(Compass compass) {

  super(compass);

 /*

  * (non-Javadoc)

  * @see org.compass.core.support.search.CompassSearchHelper#doProcessBeforeDetach(org.compass.core.support.search.CompassSearchCommand,

  *      org.compass.core.CompassSession, org.compass.core.CompassHits, int,

  *      int)

 @Override

 protected void doProcessBeforeDetach(CompassSearchCommand searchCommand,

   CompassSession session, CompassHits hits, int from, int size) {

  if (from < 0) {

   from = 0;

   size = hits.getLength();

  if (highlightFields == null) {

   return;

  // highlight fields

  for (int i = from; i < size; i++) {

   for (String highlightField : highlightFields) {

    hits.highlighter(i).fragment(highlightField);

最後就剩下簡單的搜尋頁面和顯示頁面了。

這是搜尋頁主要的代碼。

本文轉自 weijie@java 51CTO部落格,原文連結:http://blog.51cto.com/weijie/74363,如需轉載請自行聯系原作者