用compass实现站内全文搜索引擎(二)接下来是要建立搜索的服务类
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.compass.core.Compass; import org.compass.core.CompassCallback; import org.compass.core.CompassException; import org.compass.core.CompassHighlighter; import org.compass.core.CompassHits; import org.compass.core.CompassQuery; import org.compass.core.CompassSession; import org.compass.core.CompassTemplate; import org.compass.core.CompassTransaction; import cn.rgcenter.entity.Article; public class SearchServiceBean { private Compass compass; /** 索引查询 * */ public Map find(final String keywords, final String type, final int start, final int end) { CompassTemplate ct = new CompassTemplate(compass); return ct.execute(new CompassCallback<Map>() { public Map doInCompass(CompassSession session) throws CompassException { List result = new ArrayList(); int totalSize = 0; Map container = new HashMap(); CompassQuery query = session.queryBuilder().queryString( keywords).toQuery(); CompassHits hits = query.setAliases(type).hits(); totalSize = hits.length(); container.put("size", totalSize); int max = 0; if (end < hits.length()) { max = end; } else { max = hits.length(); } if(type.equals("article")){ for (int i = start; i < max; i++) { Article article = (Article) hits.data(i); String title = hits.highlighter(i).fragment("title"); if (title != null) { article.setTitle(title); } String content = hits.highlighter(i).setTextTokenizer( CompassHighlighter.TextTokenizer.AUTO) .fragment("content"); if (content != null) { article.setContent(content); } result.add(article); } } container.put("result", result); return container; } }); } public Compass getCompass() { return compass; } public void setCompass(Compass compass) { this.compass = compass; } } 索引的查询主要是根据传过来的参数,关键字keywords,是搜索的关键字,类型type,先判断是不是要搜索文章,因为一般来说,页面的搜索引擎不单单只搜索文章一个实体. 至于int 和end是为了分页取出部分结果的. String title = hits.highlighter(i).fragment("title");这段是检索titile这个属性有没有出现搜索的关键字,有就将它高亮(其实就是在关键字前后加个<font></font>的html标记设置颜色,等下可以看到在配置文件里可以自由设置高亮的颜色). String content = hits.highlighter(i).setTextTokenizer( CompassHighlighter.TextTokenizer.AUTO) .fragment("content"); 这段代码和上面的title具有一样的一样的功能,另外还多了个很重要的功能,自动选择正文中最匹配关键字的内容中的一部分输出。因为很多时候一篇文章几千字,我们只想显示有关键字的那部分的摘要,这时候这个功能就很方便. 这之后还要写一个建立索引的服务类,让服务器启动的时候或者定时重建索引.
import org.compass.gps.CompassGps; import org.springframework.beans.factory.InitializingBean; public class CompassIndexBuilder implements InitializingBean { // 是否需要建立索引,可被设置为false使本Builder失效. private boolean buildIndex = false; // 索引操作线程延时启动的时间,单位为秒 private int lazyTime = 10; // Compass封装 private CompassGps compassGps; // 索引线程 private Thread indexThread = new Thread() { @Override public void run() { try { Thread.sleep(lazyTime * 1000); System.out.println("begin compass index..."); long beginTime = System.currentTimeMillis(); // 重建索引. // 如果compass实体中定义的索引文件已存在,索引过程中会建立临时索引, // 索引完成后再进行覆盖. compassGps.index(); long costTime = System.currentTimeMillis() - beginTime; System.out.println("compss index finished."); System.out.println("costed " + costTime + " milliseconds"); } catch (InterruptedException e) { e.printStackTrace(); } } }; /** * 实现<code>InitializingBean</code>接口,在完成注入后调用启动索引线程. */ public void afterPropertiesSet() throws Exception { if (buildIndex) { indexThread.setDaemon(true); indexThread.setName("Compass Indexer"); indexThread.start(); } } public void setBuildIndex(boolean buildIndex) { this.buildIndex = buildIndex; } public void setLazyTime(int lazyTime) { this.lazyTime = lazyTime; } public void setCompassGps(CompassGps compassGps) { this.compassGps = compassGps; } } 实现了spring的InitializingBean接口,让服务器启动,bean初始化的时候去建立索引 剩下的就是配置文件了
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www./schema/beans" xmlns:xsi="http://www./2001/XMLSchema-instance" xmlns:aop="http://www./schema/aop" xmlns:tx="http://www./schema/tx" xsi:schemaLocation="http://www./schema/beans http://www./schema/beans/spring-beans-2.5.xsd http://www./schema/aop http://www./schema/aop/spring-aop-2.5.xsd http://www./schema/tx http://www./schema/tx/spring-tx-2.5.xsd"> <bean id="annotationConfiguration" class="org.compass.annotations.config.CompassAnnotationsConfiguration"> </bean> <!-- compass Bean --> <bean id="compass" class="org.compass.spring.LocalCompassBean"> <property name="compassConfiguration" ref="annotationConfiguration" /> <!-- 数据索引存储位置 --> <property name="connection"> <value>/compass/indexes</value> </property> <property name="transactionManager" ref="transactionManager" /> <property name="compassSettings"> <props> <prop key="compass.transaction.factory"> org.compass.spring.transaction.SpringSyncTransactionFactory </prop> <prop key="compass.engine.highlighter.default.formatter.simple.pre"> <![CDATA[<span style='background-color:yellow;color:red;'>]]> </prop> <prop key="compass.engine.highlighter.default.formatter.simple.post"> <![CDATA[</span>]]> </prop> <!--定义分词器--> <prop key="compass.engine.analyzer.default.type"> org.mira.lucene.analysis.IK_CAnalyzer </prop> </props> </property> <property name="classMappings"> <list> <value>cn.rgcenter.entity.Article</value> </list> </property> </bean> <!--hibernate驱动--> <bean id="hibernateGpsDevice" class="org.compass.spring.device.hibernate.dep.SpringHibernate3GpsDevice"> <property name="name"> <value>hibernateDevice</value> </property> <property name="sessionFactory" ref="sessionFactory" /> <property name="mirrorDataChanges"> <value>true</value> </property> </bean> <!-- 数据库中的数据变化后同步更新索引 --> <bean id="hibernateGps" class="org.compass.gps.impl.SingleCompassGps" init-method="start" destroy-method="stop"> <property name="compass"> <ref bean="compass" /> </property> <property name="gpsDevices"> <list> <bean class="org.compass.spring.device.SpringSyncTransactionGpsDeviceWrapper"> <property name="gpsDevice" ref="hibernateGpsDevice" /> </bean> </list> </property> </bean> <!-- compass模版 --> <bean id="compassTemplate" class="org.compass.core.CompassTemplate"> <property name="compass" ref="compass" /> </bean> <!-- 定时重建索引(利用quartz)或随Spring ApplicationContext启动而重建索引 --> <bean id="compassIndexBuilder" class="cn.rgcenter.compass.service.CompassIndexBuilder" lazy-init="false"> <property name="compassGps" ref="hibernateGps" /> <property name="buildIndex" value="true" /> <property name="lazyTime" value="5" /> </bean> <!-- 搜索引擎服务类 --> <bean id="searchService" class="cn.rgcenter.compass.service.SearchServiceBean"> <property name="compass"> <ref bean="compass" /> </property> </bean> <!-- 搜索引擎Action --> <bean id="searchAction" class="cn.rgcenter.action.SearchAction"> <property name="searchService"> <ref bean="searchService" /> </property> </bean> </beans> 至于action就不列出代码了,很简单了,只需要传搜索方法的那几个参数过去就可以了. 最后看一下搜索结果示例图: |
|