- 浏览: 520246 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (422)
- 重要 (12)
- BUG解决备忘录 (32)
- 环境搭建 (17)
- 开源组件 (4)
- 数据库 (16)
- 设计模式 (4)
- 测试 (3)
- javascript (5)
- Android (14)
- jdk相关 (9)
- struts2 (10)
- freemark (3)
- 自定义扩展及工具类 (5)
- jdk5新特性及java基础 (13)
- ssh及其他框架 (15)
- linux (32)
- tcp-ip http协议 (8)
- 服务器集群与负载均衡 (34)
- 项目管理相关 (11)
- 实用小技术 (10)
- 架构相关 (14)
- firefox组件 (11)
- spider (6)
- 产品设计 (11)
- PHP (1)
- ws (4)
- lucene (10)
- 其他 (2)
- BI (1)
- NoSQL (3)
- gzip (1)
- ext (4)
- db (6)
- socket (1)
- 源码阅读 (2)
- NIO (2)
- 图片处理 (1)
- java 环境 (2)
- 项目管理 (4)
- 从程序员到项目经理(一):没有捷径 (1)
- bug (1)
- JAVA BASE (8)
- 技术原理 (0)
- 新框架新技术 (1)
- 量化与python (1)
- 系统编程 (0)
- C语言 (0)
- 汇编 (0)
- 算法 (0)
最新评论
-
hyspace:
别逗了,最后一个算法根本不是最优的,sort(function ...
数组去重——一道前端校招试题 -
washingtin:
楼主能把策略和路由的类代码贴出来吗
Spring + iBatis 的多库横向切分简易解决思路 -
sdyjmc:
初略看了一下,没有闹明白啊,均衡负载使用Nginx,sessi ...
J2EE集群原理 I -
shandeai520:
谢谢大神!请教大神一个问题:假如我有三台服务器,连接池的上限是 ...
集群和数据库负载均衡的研究 -
hekuilove:
给lz推荐一下apache commonsStringUtil ...
request 获取 ip
在新架构中打算选择Compass或Hibernate Search作为搜索引擎框架,比较后,感觉Hibernate Search上还是没有Compass成熟,另外考虑到后期对网页的爬取及搜索需求,决定还是基于Compass来作为架构缺省的搜索引擎。网上关于 Compass的文档很多,但说得相对完整其详细的入门文档基本上没有,Compass的官方文档倒是说得很详细,但是例子一塌糊涂,存在很大问题。记录 一下搭建的过程,作为入门的指南。
Compass 通过OSEM(Object/Search Engine Mapping)允许把应用对象的领域模型映射到搜索引擎,最终通过访问common meta data来达到访问对象的目的。
1、几个核心概念
1.1、annotation vs. xml配置文件
Compass的配置文件主要分成三类:
第一类:*.cmd.xml文件*
.cmd.xml文件是对common meta data进行定义,定义了最终搜索的结果中的最基本的元数据。
第二类:*.cpm.xml文件
*.cpm.xml是Object/Search Engine Mapping,提供了POJO到common meta data的映射。
第三类:*.cfg.xml文件
Compass的*.cfg.xml定义了Compass的Index存放路径、搜索引擎分词等相关信息。
与采用xml配置文件相比较,采用Annonation方式还是相对简单,尤其是采用Spring时候,不用写*.cmd.xml文 件、*.cpm.xml、*.cfg.xml,相对很方便,而且不像Hibernate的Annonation很多,Compass的 Annonation的核心标注只有@Searchable、@SearchableId、@SearchableProperty、 @SearchableComponent个,很容易记忆。因此推荐使用Annonation方式
1.2、Compass核心API
Compass的核心API借鉴了Hibernate的术语,因此在操作上基本上与Hibernate类似,以下为Compass的几个核心接口:
CompassConfiguration(类似Hibernate Configuration):用来在一些设置参数、配置文件和映射定义上配置Compass。通常用来创建Compass接口。
Compass(类似Hibernate SessionFactory):为单线程使用,创建线程安全的实例来打开Compass Seesion。同样还提供了一些搜索引擎索引级别的操作。
CompassSesssion(类似Hibernate Session):用来执行像保存、删除、查找、装载这样的搜索操作。很轻量但是并不是线程安全的。
CompassTransaction(类似Hibernate Transaction):管理Compass事务的接口。使用它并不需要事务管理环境(像Spring、JTA)。
1.3、Compass与Spring集成
Compass已经对对spring集成做了很好的封装,同时与Spring对Hibernate的支持类似,Compass也提供了 CompassTemplate来简化诸如对Session、Transaction、Exception等操作,尽量充分使用此工具,可以有效提高效 率。例如:
CompassTemplate ct = (CompassTemplate) context.getBean(“compassTemplate”);
Article article = new Article();
article.setTitle(“Compass Test”);
article.setPublishDate(new Date());
article.setAuthor(1);
ct.save(article); //存储对象需要索引的数据到Compass的索引中。
2、软件环境
Spring :2.5
Compas:1.2.1
Hibernate:3.2.5
Mysql :5.0.5
3、数据库脚本
CREATE TABLE `article` ( `Id` int (11) NOT NULL auto_increment, `title` varchar (40) NOT NULL default '' , `author` int (11) default '0' , `publish_date` date NOT NULL default '0000-00-00' , PRIMARY KEY (`Id`) ) TYPE=MyISAM; CREATE TABLE `author` ( `Id` int (11) NOT NULL auto_increment, `username` varchar (20) NOT NULL default '' , `password` varchar (20) NOT NULL default '' , `age` smallint (6) default '0' , PRIMARY KEY (`Id`) ) TYPE=MyISAM;
4、测试用例
从测试用例讲起比较容易把关系理清楚,不然一堆术语和概念很让人晕乎。
import org.apache.log4j.Logger; import java.util.Date; import junit.framework.TestCase; import org.compass.core.Compass; import org.compass.core.CompassDetachedHits; import org.compass.core.CompassHit; import org.compass.core.CompassHits; import org.compass.core.CompassSession; import org.compass.core.CompassTemplate; import org.compass.core.CompassTransaction; import org.compass.core.support.search.CompassSearchCommand; import org.compass.core.support.search.CompassSearchResults; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.mobilesoft.esales.dao.hibernate.ArticleDAO; import com.mobilesoft.esales.dao.hibernate.AuthorDAO; import com.mobilesoft.esales.model.Article; import com.mobilesoft.esales.model.Author; import com.mobilesoft.framework.search.service.CompassSearchService; /** * Compass服务使用的测试用例 * * @author liangchuan@mobile-soft.cn * */ public class TestCompass extends TestCase { private static final Logger logger = Logger.getLogger(TestCompass.class ); private static ClassPathXmlApplicationContext context = null ; private static CompassTemplate ct; static { context = new ClassPathXmlApplicationContext(new String[] { "applicationContext.xml" , "applicationContext-resources.xml" , "applicationContext-dao.xml" , "applicationContext-service.xml" , "applicationContext-compass.xml" }); ct = (CompassTemplate) context.getBean("compassTemplate" ); } protected void setUp() throws Exception { } /** * 插入测试数据 */ public void testInsert() { ArticleDAO articleDao = (ArticleDAO) context.getBean("articleDAO" ); AuthorDAO authorDao = (AuthorDAO) context.getBean("authorDAO" ); Article article = new Article(); Author author = new Author(); author.setAge((short ) 27); author.setUsername("liangchuan" ); author.setPassword("liangchuan" ); article.setTitle("Compass Test" ); article.setPublishDate(new Date()); article.setAuthor(1); authorDao.save(author); articleDao.save(article); ct.save(article); ct.save(author); } /** * 用于测试使用CompassTransaction事务方式 */ public void testTransactionalFind() { Compass compass = ct.getCompass(); CompassSession session = compass.openSession(); CompassTransaction tx = null ; try { tx = session.beginTransaction(); CompassHits hits = session.find("Compass*" ); logger.error("testTransactionalFind() - CompassHits hits=" + hits.getLength()); for (int i = 0; i < hits.getLength(); i++) { Object hit = hits.data(i); if (hit instanceof Article) { Article item = (Article) hit; logger.error("testTransactionalFind() - article hits=" + item.getTitle()); } else if (hit instanceof Author) { Author item = (Author) hit; logger.error("testTransactionalFind() - author hits=" + item.getUsername()); } else { logger.error("testTransactionalFind() - error hits=" ); } } tx.commit(); } catch (Exception e) { if (tx != null ) { tx.rollback(); } } finally { session.close(); } } /** * 用于演示CompassDetachedHits的使用。 * 由于CompassTempalte得到的结果集必须在transactionalcontext中才能使用, * 因此必须使用CompassDetachedHits方式测试CompassDetachedHits方式 */ public void testDetachedFind() { // 由于CompassTempalte得到的结果集必须在transactional // context中才能使用,因此必须使用CompassDetachedHits方式 // 测试CompassDetachedHits方式 CompassDetachedHits hits = ct.findWithDetach("Compass*" ); logger.error("testDetachedFind() - CompassHits hits=" + hits.getLength()); for (int i = 0; i < hits.getLength(); i++) { Object hit = hits.data(i); if (hit instanceof Article) { Article item = (Article) hit; logger.error("testDetachedFind() - article hits=" + item.getTitle()); } else if (hit instanceof Author) { Author item = (Author) hit; logger.error("testDetachedFind() - author hits=" + item.getUsername()); } else { logger.error("testDetachedFind() - error hits=" ); } } } /** * 用于演示com.mobilesoft.framework.search.service.CompassSearchService的使用 * */ class CompassSearch extends CompassSearchService{ CompassSearch(){ Compass compass = ct.getCompass(); CompassSession session = compass.openSession(); CompassTransaction tx = null ; try { tx = session.beginTransaction(); CompassSearchCommand command = new CompassSearchCommand(); command.setQuery("Compass" ); CompassSearchResults results= performSearch(command,session); logger.error("CompassSearch() - CompassHit TotalHits value=" +results.getTotalHits()); for (int i = 0; i < results.getHits().length; i++) { CompassHit hits=results.getHits()[i]; Object hit=hits.getData(); logger.error("CompassSearch() - CompassHit hit=" + hit); //$NON-NLS-1$ if (hit instanceof Article) { Article item = (Article) hit; logger.error("testCompassSearchService() - article hits=" + item.getTitle()); } else if (hit instanceof Author) { Author item = (Author) hit; logger.error("testCompassSearchService() - author hits=" + item.getUsername()); } else { logger.error("testCompassSearchService() - error hits=" ); } tx.commit(); } } catch (Exception e) { if (tx != null ) { tx.rollback(); } } finally { session.close(); } } } public void testCompassSearchService() { new CompassSearch(); } protected void tearDown() throws Exception { } }
5、配置文件
applicationContext-compass.xml
<? xml version ="1.0" ?> <! DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd" > < beans default-lazy-init ="true" > < bean id ="compassTemplate" class ="org.compass.core.CompassTemplate" > < property name ="compass" ref ="compass" /> </ bean > < bean id ="annotationConfiguration" class ="org.compass.annotations.config.CompassAnnotationsConfiguration" > </ bean > < bean id ="compass" class ="org.compass.spring.LocalCompassBean" > < property name ="classMappings" > < list > < value > com.mobilesoft.esales.model.Article</ value > < value > com.mobilesoft.esales.model.Author</ value > </ list > </ property > < property name ="compassConfiguration" ref ="annotationConfiguration" /> < property name ="compassSettings" > < props > < prop key ="compass.engine.connection" > file://compass </ prop > < prop key ="compass.transaction.factory" > org.compass.spring.transaction.SpringSyncTransactionFactory </ prop > < prop key ="compass.engine.highlighter.default.formatter.simple.pre" > <! [CDATA[< font color ="red" >< b > ]]> </ prop > < prop key ="compass.engine.highlighter.default.formatter.simple.post" > <! [CDATA[</ b ></ font > ]]> </ prop > </ props > </ property > < property name ="transactionManager" ref ="transactionManager" /> </ bean > < bean id ="hibernateGpsDevice" class ="org.compass.gps.device.hibernate.HibernateGpsDevice" > < property name ="name" > < value > hibernateDevice</ value > </ property > < property name ="sessionFactory" ref ="sessionFactory" /> < property name ="mirrorDataChanges" > < value > true</ value > </ property > </ 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 > < bean class ="org.compass.spring.device.SpringSyncTransactionGpsDeviceWrapper" > < property name ="gpsDevice" ref ="hibernateGpsDevice" /> </ bean > </ list > </ property > </ bean > < bean id ="compassSearchService" class ="com.mobilesoft.framework.search.service.CompassSearchService" > < property name ="compass" ref ="compass" /> < property name ="pageSize" value ="15" /> </ bean > <!-- 定时重建索引(利用quartz)或随Spring ApplicationContext启动而重建索引 --> < bean id ="compassIndexBuilder" class ="com.mobilesoft.framework.search.service.CompassIndexBuilder" lazy-init ="false" > < property name ="compassGps" ref ="compassGps" /> < property name ="buildIndex" value ="false" /> < property name ="lazyTime" value ="10" /> </ bean > </ beans >.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas,"Courier New",courier,monospace; background-color: rgb(255, 255, 255); }.csharpcode pre { margin: 0em; }.csharpcode .rem { color: rgb(0, 128, 0); }.csharpcode .kwrd { color: rgb(0, 0, 255); }.csharpcode .str { color: rgb(0, 96, 128); }.csharpcode .op { color: rgb(0, 0, 192); }.csharpcode .preproc { color: rgb(204, 102, 51); }.csharpcode .asp { background-color: rgb(255, 255, 0); }.csharpcode .html { color: rgb(128, 0, 0); }.csharpcode .attr { color: rgb(255, 0, 0); }.csharpcode .alt { background-color: rgb(244, 244, 244); width: 100%; margin: 0em; }.csharpcode .lnum { color: rgb(96, 96, 96); } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas,"Courier New",courier,monospace; background-color: rgb(255, 255, 255); }.csharpcode pre { margin: 0em; }.csharpcode .rem { color: rgb(0, 128, 0); }.csharpcode .kwrd { color: rgb(0, 0, 255); }.csharpcode .str { color: rgb(0, 96, 128); }.csharpcode .op { color: rgb(0, 0, 192); }.csharpcode .preproc { color: rgb(204, 102, 51); }.csharpcode .asp { background-color: rgb(255, 255, 0); }.csharpcode .html { color: rgb(128, 0, 0); }.csharpcode .attr { color: rgb(255, 0, 0); }.csharpcode .alt { background-color: rgb(244, 244, 244); width: 100%; margin: 0em; }.csharpcode .lnum { color: rgb(96, 96, 96); }
applicationContext-dao.xml、applicationContext-service.xml、applicationContext-resources.xml等略去。
6、Service层(参考了SpringSide实现)
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas,"Courier New",courier,monospace; background-color: rgb(255, 255, 255); }.csharpcode pre { margin: 0em; }.csharpcode .rem { color: rgb(0, 128, 0); }.csharpcode .kwrd { color: rgb(0, 0, 255); }.csharpcode .str { color: rgb(0, 96, 128); }.csharpcode .op { color: rgb(0, 0, 192); }.csharpcode .preproc { color: rgb(204, 102, 51); }.csharpcode .asp { background-color: rgb(255, 255, 0); }.csharpcode .html { color: rgb(128, 0, 0); }.csharpcode .attr { color: rgb(255, 0, 0); }.csharpcode .alt { background-color: rgb(244, 244, 244); width: 100%; margin: 0em; }.csharpcode .lnum { color: rgb(96, 96, 96); }AdvancedSearchCommand.java
package com.mobilesoft.framework.search.service; import java.util.HashSet; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.compass.core.CompassQuery.SortDirection; import org.compass.core.CompassQuery.SortPropertyType; import org.compass.core.support.search.CompassSearchCommand; import org.springframework.util.Assert; public class AdvancedSearchCommand extends CompassSearchCommand { /** * 封装基于Compass 的排序参数. */ class CompassSort { private String name; private SortPropertyType type; private SortDirection direction; public CompassSort() { } public CompassSort(String sortParamName, String paramType, boolean isAscend) { Assert.isTrue(StringUtils.isNotBlank(sortParamName)); setName(sortParamName); if ("int" .equalsIgnoreCase(paramType)) { setType(SortPropertyType.INT); } else if ("float" .equalsIgnoreCase(paramType)) { setType(SortPropertyType.FLOAT); } else if ("string" .equalsIgnoreCase(paramType)) { setType(SortPropertyType.STRING); } else { setType(SortPropertyType.AUTO); } if (isAscend) { setDirection(SortDirection.AUTO); } else { setDirection(SortDirection.REVERSE); } } public String getName() { return name; } public void setName(String name) { this .name = name; } public SortPropertyType getType() { return type; } public void setType(SortPropertyType type) { this .type = type; } public SortDirection getDirection() { return direction; } public void setDirection(SortDirection direction) { this .direction = direction; } } /** * 搜索结果排序表. */ private Set<CompassSort> sortMap = new HashSet<CompassSort>(); private String[] highlightFields; /** * @param paramType 现定义了三种类型: int string 以及 float。<br> * 除去这三种外,其他会被自动定义为SortPropertyType.AUTO 具体的可见{@link org.compass.core.CompassQuery.SortPropertyType} * @param isAscend 顺序还是倒序排序 * @see org.compass.core.CompassQuery.SortPropertyType#AUTO * @see org.compass.core.CompassQuery.SortPropertyType#INT * @see org.compass.core.CompassQuery.SortPropertyType#STRING * @see org.compass.core.CompassQuery.SortPropertyType#FLOAT * @see org.compass.core.CompassQuery.SortDirection#AUTO * @see org.compass.core.CompassQuery.SortDirection#REVERSE */ public void addSort(String sortParamName, String paramType, boolean isAscend) { this .sortMap.add(new CompassSort(sortParamName, paramType, isAscend)); } public Set<CompassSort> getSortMap() { return sortMap; } public void setSortMap(Set<CompassSort> sortMap) { this .sortMap = sortMap; } public String[] getHighlightFields() { return highlightFields; } public void setHighlightFields(String[] highlightFields) { this .highlightFields = highlightFields; } }
CompassIndexBuilder.java
package com.mobilesoft.framework.search.service; import org.apache.log4j.Logger; import org.compass.gps.CompassGps; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; /** * 通过quartz定时调度定时重建索引或自动随Spring ApplicationContext启动而重建索引的Builder. * 会启动后延时数秒新开线程调用compassGps.index()函数. * 默认会在Web应用每次启动时重建索引,可以设置buildIndex属性为false来禁止此功能. * 也可以不用本Builder, 编写手动调用compassGps.index()的代码. * */ public class CompassIndexBuilder implements InitializingBean { private static final Logger log = Logger.getLogger(CompassIndexBuilder.class ); // 是否需要建立索引,可被设置为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); log.info("begin compass index..." ); long beginTime = System.currentTimeMillis(); // 重建索引. // 如果compass实体中定义的索引文件已存在,索引过程中会建立临时索引, // 索引完成后再进行覆盖. compassGps.index(); long costTime = System.currentTimeMillis() - beginTime; log.info("compss index finished." ); log.info("costed " + costTime + " milliseconds" ); } catch (InterruptedException e) { // simply proceed } } }; /** * 实现<code>InitializingBean</code>接口,在完成注入后调用启动索引线程. * * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() */ public void afterPropertiesSet() throws Exception { if (buildIndex) { Assert.notNull(compassGps, "CompassIndexBuilder not set CompassGps yet." ); 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; } }
CompassSearchService.java
package com.mobilesoft.framework.search.service; import org.compass.core.Compass; import org.compass.core.CompassCallback; import org.compass.core.CompassDetachedHits; 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 org.compass.core.support.search.CompassSearchCommand; import org.compass.core.support.search.CompassSearchResults; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; import com.mobilesoft.framework.search.service.AdvancedSearchCommand.CompassSort; /** * 仿照 {@link org.compass.spring.web.mvc.CompassSearchController} * 中的代码,构建了一个Service,方便不使用Spring MVC * * @see org.compass.spring.web.mvc.CompassSearchController * @see org.compass.spring.web.mvc.AbstractCompassCommandController */ public class CompassSearchService implements InitializingBean { //每页显示的条目数量 private Integer pageSize = 15; private Compass compass; private CompassTemplate compassTemplate; /** * 公开的搜索接口,返回匹配的搜索结果,与 * {@link org.compass.spring.web.mvc.CompassSearchController#handle(javax.servlet.http.HttpServletRequest, *javax.servlet.http.HttpServletResponse,Object,org.springframework.validation.BindException) 处理相似 * * @see org.compass.spring.web.mvc.CompassSearchController#handle(javax.servlet.http.HttpServletRequest, *javax.servlet.http.HttpServletResponse,java.lang.Object,org.springframework.validation.BindException) */ public CompassSearchResults search(final CompassSearchCommand command) { return (CompassSearchResults) getCompassTemplate().execute( CompassTransaction.TransactionIsolation.READ_ONLY_READ_COMMITTED, new CompassCallback() { public Object doInCompass(CompassSession session) { return performSearch(command, session); } }); } /** * 通过此方法调用搜索引擎,进行结果匹配搜索. * * @see org.compass.spring.web.mvc.CompassSearchController#performSearch( *org.compass.spring.web.mvc.CompassSearchCommand,org.compass.core.CompassSession) */ protected CompassSearchResults performSearch(CompassSearchCommand searchCommand, CompassSession session) { long time = System.currentTimeMillis(); CompassQuery query = buildQuery(searchCommand, session); CompassHits hits = query.hits(); CompassDetachedHits detachedHits; CompassSearchResults.Page[] pages = null ; if (pageSize == null ) { doProcessBeforeDetach(searchCommand, session, hits, -1, -1); detachedHits = hits.detach(); } else { int iPageSize = pageSize; int page = 0; int hitsLength = hits.getLength(); if (searchCommand.getPage() != null ) { page = searchCommand.getPage(); } int from = page * iPageSize; if (from > hits.getLength()) { // 如果起始的条目大于搜索到的条目 from = hits.getLength() - iPageSize; doProcessBeforeDetach(searchCommand, session, hits, from, hitsLength); detachedHits = hits.detach(from, hitsLength); } else if ((from + iPageSize) > hitsLength) { // 结束的条目大于搜索到的结果 doProcessBeforeDetach(searchCommand, session, hits, from, hitsLength); detachedHits = hits.detach(from, hitsLength); } else { // 中间的页码,直接取出相应的条目 doProcessBeforeDetach(searchCommand, session, hits, from, iPageSize); detachedHits = hits.detach(from, iPageSize); } doProcessAfterDetach(searchCommand, session, detachedHits); int numberOfPages = (int ) Math.ceil((float ) hitsLength / iPageSize); pages = new CompassSearchResults.Page[numberOfPages]; for (int i = 0; i < pages.length; i++) { pages[i] = new CompassSearchResults.Page(); pages[i].setFrom(i * iPageSize + 1); pages[i].setSize(iPageSize); pages[i].setTo((i + 1) * iPageSize); if (from >= (pages[i].getFrom() - 1) && from < pages[i].getTo()) { pages[i].setSelected(true ); } else { pages[i].setSelected(false ); } } if (numberOfPages > 0) { CompassSearchResults.Page lastPage = pages[numberOfPages - 1]; if (lastPage.getTo() > hitsLength) { lastPage.setSize(hitsLength - lastPage.getFrom()); lastPage.setTo(hitsLength); } } } time = System.currentTimeMillis() - time; CompassSearchResults searchResults = new CompassSearchResults(detachedHits.getHits(), time, pageSize); searchResults.setPages(pages); return searchResults; } /** * 构建Lucene搜索器. */ protected CompassQuery buildQuery(CompassSearchCommand searchCommand, CompassSession session) { CompassQuery query = session.queryBuilder().queryString(searchCommand.getQuery().trim()).toQuery(); if (AdvancedSearchCommand.class .isAssignableFrom(searchCommand.getClass())) { AdvancedSearchCommand advancedSearchCommand = (AdvancedSearchCommand) searchCommand; for (CompassSort sort : advancedSearchCommand.getSortMap()) { query.addSort(sort.getName(), sort.getType(), sort.getDirection()); } } return query; } /** * 在detach 之前,可以做一些操作。比如highlighting... * * @param from 需要注意的是,如果pageSize 没有指定,那么这里传入的参数为-1 */ protected void doProcessBeforeDetach(CompassSearchCommand searchCommand, CompassSession session, CompassHits hits, int from, int size) { if (AdvancedSearchCommand.class .isAssignableFrom(searchCommand.getClass())) { if (from < 0) { from = 0; size = hits.getLength(); } String[] highlightFields = ((AdvancedSearchCommand) searchCommand).getHighlightFields(); if (highlightFields == null ) { return ; } // highlight fields for (int i = from; i < size; i++) { for (String highlightField : highlightFields) { hits.highlighter(i).fragment(highlightField); } } } } /** * An option to perform any type of processing before the hits are detached. */ protected void doProcessAfterDetach(CompassSearchCommand searchCommand, CompassSession session, CompassDetachedHits hits) { } public void afterPropertiesSet() throws Exception { Assert.notNull(compass, "Must set compass property" ); this .compassTemplate = new CompassTemplate(compass); } public Integer getPageSize() { return pageSize; } public void setPageSize(Integer pageSize) { this .pageSize = pageSize; } public void setCompass(Compass compass) { this .compass = compass; } protected CompassTemplate getCompassTemplate() { return this .compassTemplate; } }
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas,"Courier New",courier,monospace; background-color: rgb(255, 255, 255); }.csharpcode pre { margin: 0em; }.csharpcode .rem { color: rgb(0, 128, 0); }.csharpcode .kwrd { color: rgb(0, 0, 255); }.csharpcode .str { color: rgb(0, 96, 128); }.csharpcode .op { color: rgb(0, 0, 192); }.csharpcode .preproc { color: rgb(204, 102, 51); }.csharpcode .asp { background-color: rgb(255, 255, 0); }.csharpcode .html { color: rgb(128, 0, 0); }.csharpcode .attr { color: rgb(255, 0, 0); }.csharpcode .alt { background-color: rgb(244, 244, 244); width: 100%; margin: 0em; }.csharpcode .lnum { color: rgb(96, 96, 96); }
8、Model层
@SearchableId 声明Document的id列;
@SearchableProperty 声明要索引的field;
@SearchableComponent 声明要索引的其他关联对象。
Article.java
package com.mobilesoft.esales.model; import java.util.Date; import org.compass.annotations.Searchable; import org.compass.annotations.SearchableId; import org.compass.annotations.SearchableProperty; import org.compass.core.CompassTemplate; @Searchable public class Article implements java.io.Serializable { @SearchableId private Integer id; @SearchableProperty(name="title" ) private String title; @SearchableProperty(name="author" ) private Integer author; @SearchableProperty(name="publishDate" ) private Date publishDate; /** default constructor */ public Article() { } /** minimal constructor */ public Article(String title, Date publishDate) { this .title = title; this .publishDate = publishDate; } /** full constructor */ public Article(String title, Integer author, Date publishDate) { this .title = title; this .author = author; this .publishDate = publishDate; } public Integer getId() { return this .id; } public void setId(Integer id) { this .id = id; } public String getTitle() { return this .title; } public void setTitle(String title) { this .title = title; } public Integer getAuthor() { return this .author; } public void setAuthor(Integer author) { this .author = author; } public Date getPublishDate() { return this .publishDate; } public void setPublishDate(Date publishDate) { this .publishDate = publishDate; } }.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas,"Courier New",courier,monospace; background-color: rgb(255, 255, 255); }.csharpcode pre { margin: 0em; }.csharpcode .rem { color: rgb(0, 128, 0); }.csharpcode .kwrd { color: rgb(0, 0, 255); }.csharpcode .str { color: rgb(0, 96, 128); }.csharpcode .op { color: rgb(0, 0, 192); }.csharpcode .preproc { color: rgb(204, 102, 51); }.csharpcode .asp { background-color: rgb(255, 255, 0); }.csharpcode .html { color: rgb(128, 0, 0); }.csharpcode .attr { color: rgb(255, 0, 0); }.csharpcode .alt { background-color: rgb(244, 244, 244); width: 100%; margin: 0em; }.csharpcode .lnum { color: rgb(96, 96, 96); }
Author.java
package com.mobilesoft.esales.model; import org.compass.annotations.Searchable; import org.compass.annotations.SearchableId; import org.compass.annotations.SearchableProperty; import org.compass.core.CompassTemplate; @Searchable public class Author implements java.io.Serializable { @SearchableId private Integer id; @SearchableProperty(name="username" ) private String username; private String password; @SearchableProperty(name="age" ) private Short age; public Author() { } /** minimal constructor */ public Author(String username, String password) { this .username = username; this .password = password; } /** full constructor */ public Author(String username, String password, Short age) { this .username = username; this .password = password; this .age = age; } // Property accessors public Integer getId() { return this .id; } public void setId(Integer id) { this .id = id; } public String getUsername() { return this .username; } public void setUsername(String username) { this .username = username; } public String getPassword() { return this .password; } public void setPassword(String password) { this .password = password; } public Short getAge() { return this .age; } public void setAge(Short age) { this .age = age; } }.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas,"Courier New",courier,monospace; background-color: rgb(255, 255, 255); }.csharpcode pre { margin: 0em; }.csharpcode .rem { color: rgb(0, 128, 0); }.csharpcode .kwrd { color: rgb(0, 0, 255); }.csharpcode .str { color: rgb(0, 96, 128); }.csharpcode .op { color: rgb(0, 0, 192); }.csharpcode .preproc { color: rgb(204, 102, 51); }.csharpcode .asp { background-color: rgb(255, 255, 0); }.csharpcode .html { color: rgb(128, 0, 0); }.csharpcode .attr { color: rgb(255, 0, 0); }.csharpcode .alt { background-color: rgb(244, 244, 244); width: 100%; margin: 0em; }.csharpcode .lnum { color: rgb(96, 96, 96); }
9、DAO层
ArticleDAO.java和AuthorDAO.java省略
直接用MyEclipse生成的,没有什么特别的。
10、参考文档
http://www.compass-project.org/docs/1.2.1/reference/html/
The Compass Framework Search made easy.pdf
InfoQ: Compass: Integrate Search into your apps
InfoQ: Compass: Simplifying and Extending Lucene to Provide Google-like Search
发表评论
-
SolrJ
2012-07-31 20:42 0http://www.ibm.com/developerwor ... -
lucene FilteredQuery
2010-12-28 20:49 1622FilteredQuery包含两个成员变量: Query ... -
ibatis insert 返回对象
2010-12-27 23:09 1398<!-- Insert example, using t ... -
Compass入门 及于spring和ibatis结合
2010-12-23 22:31 999开始之前 什么 ... -
使用 Compass 第三方框架维护索引库数据
2010-12-22 16:59 1300使用 Compass 第三方框架维护索引库数据 ... -
Lucene搜索方法总结
2010-12-22 16:28 899更多lucene信息欢迎查看http://summerbell ... -
lucene的分组查询(类似sql的group by)的解决方法
2010-12-22 15:42 1458通过lucene搜索去除相同结果。 在网上找了很久到没有答案 ... -
MyEclipse手动修改WebRoot目录后无法打包
2010-12-17 16:04 1631环境: MyEclipse Enterpr ... -
lucene入门
2010-11-17 16:20 858最近一直再研究lucene,把入门的程序和大家分享: 对 ... -
lucene 单机 io性能提高策略
2010-11-16 13:47 989蓝山咖啡(36668534) 13:30:35 所以,首先 ...
相关推荐
### Compass入门指南:深入理解与实战应用 #### 核心概念解析 **1.1 Annotation vs. XML配置文件** 在Compass中,开发者可以选择使用Annotation或XML配置文件来进行配置。这两种方式各有优劣: - **Annotation...
下面将详细讲解Compass的基本概念、安装过程、主要功能以及如何通过它来构建入门级的网页项目。 一、Compass简介 Compass是一个开源项目,由Chris Eppstein开发,它的核心思想是提供一系列预先定义好的样式库和模块...
**入门指南** 对于初学者来说,理解Compass的基本概念和用法是关键。首先,你需要配置Compass,指定数据源和索引位置。接着,定义对象-搜索映射文件(`.cmap.xml`),将你的Java类与Lucene字段对应起来。然后,你...
**: 最基础的入门程序,用于展示如何在micro:bit上打印文本。 2. **Image**: 处理图像和显示图形的方法。 3. **Buttons**: 控制micro:bit上的按钮事件。 4. **Input/Output**: 管理输入输出设备,如传感器和显示器。...
### Lucene入门指南 #### 一、Lucene简介 **Lucene** 是一款高性能的全文检索引擎工具包,由 **Apache 软件基金会** 的 **Jakarta 项目组** 开发并维护。作为一款完全开放源代码的工具,Lucene 提供了一系列的功能...
grunt-contrib-compass v1.1.1 使用Compass将Sass编译为CSS入门如果您以前从未使用过 ,请务必查看《指南》,因为它说明了如何创建以及安装和使用Grunt插件。 熟悉该过程后,可以使用以下命令安装此插件: npm ...
foundation-compass-template, 基础指南针模板( 由CLI使用) 基础指南针模板最简单的方法来开始基础 指南针。要求ruby 1.9 node.js指南针: gem install compassBower 插件: npm install bower -g快速入门下载这个...
指南针图案入门这是指南针扩展和 rubygem 的开发库: 。使用 Sass 和 Compass 创建 HTML 和 CSS 样式指南Compass Pattern Primer是一个为您的网站或 Web 应用程序快速生成样式指南的系统。 它是可以为任何网站...
标题“githut:Symfony 3入门指南”暗示了这是一个关于学习Symfony 3框架的教程资源,可能包含了一系列的步骤、示例代码和实践指导,帮助初学者快速上手Symfony框架。 描述中的“GitHut-Symfony 3入门教程”进一步...
如果您在入门时遇到任何麻烦,可以参考以获取可能在本说明中被跳过或假定的提示。 在compass目录中,将.env.example复制到.env并填写详细信息。 使用composer安装依赖项。 $ composer install 创建数据库并在....
微信小程序提供了众多的原生API接口,利用罗盘接口,做了个简单的指南针小程序,搜索小程序【X的实验室】可看效果。...<view class='m-compass'> <image class='m-compassbg' src='img/bg.png' xss=removed></image> o
保养指南针 该应用程序是由提供的 gem生成的。 Rails Composer是开源的,并受到订户的支持。 请加入RailsApps以支持Rails Composer的开发。问题? 问题? 需要帮忙? 询问带有标签“ railsapps”的堆栈溢出。 您的...
本入门套件"starterkit-scss"就是针对使用SCSS和指南针进行网站开发而设计的,旨在帮助开发者快速上手SCSS,并利用指南针的强大功能提升工作效率。 ### SCSS核心特性 1. **变量(Variables)**:在SCSS中,你可以...
**标题解析:** "nosql入门 ----------待续" ...综上所述,这个压缩包文件的内容可能会涵盖NoSQL数据库的基础概念、类型特性、源码分析、工具使用、入门指南以及性能优化等多个方面,是学习NoSQL数据库的一个良好起点。
旅行指南针Trip Compass 是一款实用的应用程序,专为喜欢步行探索新地方/城市但不知道方向(包括我自己)的旅行者和流浪者打造。截图 更多入门安装 运行pod install 将ConfigExample.plist重命名为Config.plist 要求...
Jekyll与Foundation(Compass)快速入门(第29驱动器) 使用Jekyll&Foundation + Compass设计和开发快速入门。要求Ruby 1.9以上: gem install foundation : gem install compass : npm install bower -g : gem ...
APDPlat入门指南 APDPlat专题文章 APDPlat是Application Product Development Platform(应用级产品开发平台)的缩写。 APDPlat提供了应用容器、多模块架构、代码生成、安装程序、认证授权、备份恢复、...
作为入门,我们将从以下几个关键点来探讨MongoDB的基础知识: 1. **文档型数据库**: MongoDB是一种NoSQL数据库,它存储数据为键值对的文档形式,如BSON(Binary JSON)。这种结构允许数据以非结构化或半结构化的...