整合compass构建搜索

最近参照springside
http://wiki.springside.org.cn/display/springside/Compass
重新开发了一下网站搜索功能.
[quote]DataMirror会把数据库的增删改变化实时映射到索引文件中。

如果你采用Hibernate等ORM方案,Compass就会与Hibernate的event机制结合,或者使用AOP的方式,自动在数据库增删改时变更索引;如果你只是采用JDBC,也可以在XML文件配置Table Mapping或ResultSet Mapping,指定version列,Compasss定时对version列变化了的数据进行索引更新。

而且,Compass还支持事务,在查询数据库遍历结果集的过程中如果出现异常,会在Index Segments 文件一级进行事务控制。

如果没有Compass,我们一般会在每天深夜重建一次索引。相比Compass的做法,
一来反应迟缓,平均延时半天;
二来效率没有Compass高。如果采用完全重建索引,效率就不用说了。如果进行增量索引,就要增加一个字段,在数据更新时进行特殊的处理,删除时也不能直接删除数据,要等lucene删完索引数据才能删除,这样Lucene对应用就非常不透明了。
三来不支持事务,如果建立索引过程中出现异常,索引文件的状态是不可控的
[/quote]

---------------------------------------------------------------------
第一步,宣告待搜索的POJO!
一系列的annotation...我喜欢使用annotation
@Searchable
@SearchableId
@SearchableProperty
@SearchableComponent(refAlias="")

@Searchable(alias="article")
public class Article extends AbstractAutoID implements java.io.Serializable {


@SearchableComponent(refAlias = "column")
private ColumnModel column;
private String title;
@SearchableProperty
private String content;
private Integer hot;
private String author;
private Date loadtime;
private String srcfrom;
private Set<ArticleComment> comment;
getter/setter...


[size=small][color=red]这一步有个注意点:关联的类,在写注解的时候,要写在属性上面,不要写在get方法上面..
不然搜索到的关联类为null.[/color][/size]
而hibernate的关联注解要写get方法上,不然会报错...这是个区别...
事实不是像很多资料上写的,属性与方法上随便写...

第二步:Compass:核心定义类,定义要搜索的POJO 和 索引存储的路径。
CompassGPS: 定义使用了Hibernate3GPS,定义了init-method 和destory-method,会自动随ApplicaitonContext的启动,开始监控Hibernate的变化。
这个关键是配置文件了:
直接参考springside的就可以使用:
<bean id="compass" class="org.compass.spring.LocalCompassBean">
<!-- anontaition式设置 -->
<property name="classMappings">
<list>
<value>org.springside.bookstore.model.Book</value>
<value>org.springside.bookstore.model.Category</value>
</list>
</property>

<property name="compassConfiguration">
<bean class="org.compass.annotations.config.CompassAnnotationsConfiguration"/>
</property>

<property name="compassSettings">
<props>
<prop key="compass.engine.connection">
file://${user.home}/springside/compass
</prop>
<prop key="compass.transaction.factory">
org.compass.spring.transaction.SpringSyncTransactionFactory
</prop>
</props>
</property>

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

<!-- Compass中建立索引与mirror database change的部件 -->
<bean id="compassGps" class="org.compass.gps.impl.SingleCompassGps"
init-method="start" destroy-method="stop">
<property name="compass" ref="compass"/>
<property name="gpsDevices">
<list>
<bean class="org.compass.spring.device.hibernate.SpringHibernate3GpsDevice">
<property name="name" value="hibernateDevice"/>
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
</list>
</property>
</bean>


第三步:就是写搜索类...controller ,service..

重建索引的action..参考springside就可以了..

我使用的还是struts1.x..
public class RebuildSearchIndexAction extends Action {
private static final Logger log = Logger.getLogger(RebuildSearchIndexAction.class);



// 索引操作线程延时启动的时间,单位为秒
private int lazyTime = 10;

// Compass封装
private CompassGps compassGps;
public void setCompassGps(CompassGps compassGps) {
this.compassGps = compassGps;
}
// 索引线程
private Thread indexThread = new Thread() {

@Override
public void run() {
try {
Thread.sleep(lazyTime * 1000);
if(log.isInfoEnabled())
log.info("begin compass index...");
long beginTime = System.currentTimeMillis();
// 重建索引.
// 如果compass实体中定义的索引文件已存在,索引过程中会建立临时索引,
// 索引完成后再进行覆盖.
compassGps.index();
long costTime = System.currentTimeMillis() - beginTime;
if(log.isInfoEnabled())
log.info("compss index finished.");
if(log.isInfoEnabled())
log.info("costed " + costTime + " milliseconds");
} catch (InterruptedException e) {
// simply proceed
}
}
};


public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
indexThread.setDaemon(true);
indexThread.setName("Compass Indexer");
indexThread.start();
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = null;
try {
out = response.getWriter();
}catch (Exception e){

}
out.print("compass indexer finish!!");
return null;

}
}


一条关键语句:
compassGps.index();

不再像过去,先删除旧的,再建新的.


搜索的controller
	public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
// TODO Auto-generated method stub
String query = StringUtil.encode(request.getParameter("query"),"utf-8");
Integer pageNo = IntegerUtil.parseInt(request.getParameter("pageNo"));
String type=request.getParameter("type");
// form get request,encode charactes
if (type==null){
type = "article";
}
AdvancedSearchCommand searchCommand = new AdvancedSearchCommand();
searchCommand.setQuery(query);
searchCommand.setHighlightFields(new String[] {"title"});
searchCommand.setPage(pageNo);

searchCommand.setAlias(type);

Page page = new Page(15);
SearchResults searchResults = new SearchResults(page);
searchResults.setQuery(query);
searchResults.setAlias(type);
searchResults.setCompassSearchResults(compassSearchService.search(searchCommand,page));

request.setAttribute("searchResults",searchResults);
/**
* 根据type类型,跳转到相应的页面.
* type = article | resource
*/
return mapping.findForward(type);
}


对于service,直接使用springside里的就可以.
但不太喜欢那个分页的效果,所以我重写了下..加了一个Page类..我现在分页都是使用taglib-pager组件..使用方便.

还改了一个地方:
	/**
* 构建Lucene搜索器.
*/
protected CompassQuery buildQuery(CompassSearchCommand searchCommand,
CompassSession session) {
AdvancedSearchCommand ac = (AdvancedSearchCommand) searchCommand;
CompassBooleanQueryBuilder queryBuilder = session.queryBuilder().bool();
if (ac.getAlias() != null) {

queryBuilder.addMust(session.queryBuilder().alias(ac.getAlias()));
}
queryBuilder.addMust(session.queryBuilder().queryString(
ac.getQuery().trim()).toQuery());

这儿搜索加了个条件..搜索的alias..因为网站有文章外还有别的搜索源.....

效果可以到[url]http://www.java1995.cn[/url]上看看..只是现在还有一个乱码问题..
我使用的form method=get..自己也处理了字符编码..
但空间提供商,把server.xml中设置了URIEncode="GB2312"...我相当无语..
这个问题还在交涉....提供商的技术水平让人相当无语...
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值