用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>
</bean>
最后就是自动生成索引的页面了,这里我用的是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) {
throw new IllegalArgumentException(
"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
* search operation.
*/
public void setSearchView(String searchView) {
this.searchView = searchView;
}
/**
* Returns the name of the results that the
* {@link org.compass.core.support.search.CompassSearchResults} will be
* saved under. Defaults to "searchResults".
*/
public String getSearchResultsName() {
return searchResultsName;
}
/**
* Sets the name of the results that the
* {@link org.compass.core.support.search.CompassSearchResults} will be
* saved under. Defaults to "searchResults".
*/
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
* pagination will be used.
*
* @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.
*
* <p>
* 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 pageSize
* 每一页显示的条目数
* @param sectionSize
* 每一节显示的页数.
*/
public CompassPage(CompassHit[] elements, int pageSize, int pageNumber, int totalElements, int sectionSize, String query, long searchTime) {
super();
this.elements = elements;
this.pageSize = pageSize;
this.pageNumber = pageNumber;
this.totalElements = totalElements;
this.sectionSize = sectionSize;
this.query = query;
this.searchTime = searchTime;

if (Integer.MAX_VALUE == this.pageNumber
|| this.pageNumber > getLastPageNumber()) // last page
{
this.pageNumber = getLastPageNumber();
}
}
public String getQuery() {
return query;
}
public void setQuery(String query) {
this.query = query;
}
public CompassHit[] getElements() {
return elements;
}
public void setElements(CompassHit[] elements) {
this.elements = elements;
}
public int getPageNumber() {
return pageNumber;
}
public void setPageNumber(int pageNumber) {
this.pageNumber = pageNumber;
}
public int getSectionSize() {
return sectionSize;
}
public void setSectionSize(int sectionSize) {
this.sectionSize = sectionSize;
}
public int getTotalElements() {
return totalElements;
}
public void setTotalElements(int totalElements) {
this.totalElements = totalElements;
}
public void setPageSize(int pageSize) {
this.pageSize = 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() {
return pageSize;
}
public int getPreviousPageNumber() {
return (getThisPageNumber() == 1) ? 1 : getThisPageNumber() - 1;
}
public int getPreviousSectionFirstPageNumber() {
return (pageNumber / sectionSize - 1) * sectionSize + 1;
}
public Object getThisPageElements() {
return elements;
}
public int getThisPageFirstElementNumber() {
return (getThisPageNumber() - 1) * getPageSize() + 1;
}
public int getThisPageLastElementNumber() {
int fullPage = getThisPageFirstElementNumber() + getPageSize() - 1;
return getTotalNumberOfElements() < fullPage ? getTotalNumberOfElements()
: fullPage;
}
public int getThisPageNumber() {
return pageNumber;
}
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++) {
pagesBar.add(new Integer(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() {
return totalElements;
}
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"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/search.htm">searchController</prop>
</props>
</property>
</bean>

<!-- 搜索的控制器 -->
<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" />
</property>
</bean>
最后为了能给搜索到的结果高亮显示。还需要配置。
<!-- 高亮字段显示 -->
<bean id="advanceCompassSearchHelper"
class="com.jack.video.util.AdvanceCompassSearchHelper">
<property name="highlightFields">
<list>
<value>CName</value>
</list>
</property>
<property name="pageSize">
<value>10</value>
</property>
<constructor-arg ref="compass" />
</bean>

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);
}
}
}
}




这是搜索页主要的代码。
<form method="get" action="/search.htm">
<input type="text" size="50" name="query" value="${query?if_exists}" />
<input type="hidden" name="page" value="1"/> <input type="submit" value="搜索" />
</form>
以下是结果页的主要代码。



<#macro s_search_result data="" config=""> <script type="text/javascript"> var videoList = { channelId: ${channelId} }; </script> <div class="box"> <div class="ir_box"> <div class="title"> <@s_option_button /> <ul class="tag_menu"> <li><a class="current" href="javascript:;"><span>搜索结果</span></a></li> </ul> </div> <div class="content"> <@s_module_config data=config /> <div class="show_mode"> </div> <div class="show_mode"> <ul class="nonce_mode"> <li>共有 ${data.totalElements} 项符合 ${data.query} 的查询结果</li> <li>第 ${data.pageNumber}/${data.lastPageNumber} 页</li> <li>用时 ${data.searchTime} 毫秒</li> </ul> <ul class="choose_mode"> <li></li> <li></li> </ul> </div> <#if data.elements?exists && data.elements?has_content > <#list data.elements as d> <div class="veol_cloud"> <div class="vec_content"> <div class="vec_info"> <p> <strong>名字:</strong><@s_se v=d.data.description /> </p> <p> <strong>导演:</strong> <span class="null_director"><@s_se v=d.data.director /></span> </p> <p> <strong>类型:</strong> <span class="null_genre"><@s_se v=d.data.genre /></span> </p> </div> </div> </div> </div> </#list> <ul class="paging"> <li> <span>共有 <b>${data.totalElements}</b> 项 第 <b>${data.pageNumber}</b> / <b>${data.lastPageNumber}</b> 页</span> </li> <li> <a href="/search.htm?query=${data.query}&page=1" title="第一页">←</a> </li> <#if (data.getThisSectionFirstPageNumber()>1)> <li> <a href="/search.htm?query=${data.query}&page=${data.getThisSectionFirstPageNumber()}" title="快速向前翻10页" /><<</a> </li> </#if> <#if (data.getPreviousPageNumber()>1)> <li> <a href="/search.htm?query=${data.query}&page=${data.getPreviousPageNumber()}" title="向前翻1页" /><</a> </li> </#if> <#if data.getThisSectionPagesBar()?exists> <#list data.getThisSectionPagesBar() as d> <li> <a href="/search.htm?query=${data.query}&page=${d}">${d}</a> </li> </#list> </#if> <#if (data.getNextPageNumber()<=data.lastPageNumber)> <li> <a href="/search.htm?query=${data.query}&page=${data.getNextPageNumber()}" title="向后翻1页" />></a> </li> </#if> <#if (data.getNextSectionFirstPageNumber()<=data.lastPageNumber)> <li> <a href="/search.htm?query=${data.query}&page=${data.getNextSectionFirstPageNumber()}" title="快速向后翻10页" />>></a> </li> </#if> <li> <a href="/search.htm?query=${data.query}&page=${data.lastPageNumber}" title="最后一页">→</a> </li> </ul> <#else> 暂无相关影片 </#if> </div> </div> </div></#macro>


现在把快速给你的网站搭建搜索功能已讲完。写的过程中可能有不对的地方,希望你在调试的时候该过来。基本的实现原理及过程已讲了,至于如何用,就看你自己来。我主要快速的把要点讲了一下。里面还有很多细节。有时间的话再和大家讨论。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值