Blog信息 |
blog名称: 日志总数:1304 评论数量:2242 留言数量:5 访问次数:7626694 建立时间:2006年5月29日 |

| |
[Java Open Source]Compass读文档笔记 软件技术
lhwork 发表于 2006/11/24 10:52:22 |
Compass是基于Lucene
的更高层的抽象,假如你正打算做关于搜索方面的模块的话,那我建议你使用Compass,他提供了可配置方案,而且比Lucene更加容易使用。如果你的系统中使用Spring,
Hibernate,JDO, IBatis。。。 Compass是最好的选择,他能够非常方便的集成到现有系统中去。
1. Compass的framework的系统结构。
感觉Compass的代码的结构简直就是剽窃Hibernate的,可能Compass的最初目的是用来整合Hibernate的,
CompassConfiguration conf = new CompassConfiguration().configure().addClass(Author.class);Compass compass = conf.buildCompass();CompassSession session = compass.openSession();CompassTransaction tx = null;try { tx = session.beginTransaction(); ... session.save(author); CompassHits hits = session.find("jack london"); Author a = (Author) hits.data(0); Resource r = hits.getResource(0); ... tx.commit();} catch (CompassException ce) { if (tx != null) tx.rollback();} finally { session.close();}假如你对Hibernate有了解的话,相信你对Compass会比较容易理解的,你可以把Hibernate的思想转移到Compass上。现在让我们看看他们之间的相似吧。compass.cfg.xml
<compass-core-config
xmlns="http://www.opensymphony.com/compass/schema/core-config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opensymphony.com/compass/schema/core-config http://www.opensymphony.com/compass/schema/compass-core-config.xsd"> <compass name="default"> <connection> <file path="target/test-index"/> </connection> <mappings> <class name="test.Author" /> </mappings> </compass></compass-core-config> 这个是Compass总的配置文件,其中定义了索引文件存储的位置(这里是用文件系统,Compass有多种选择,你也可以选数据库或其他),Compass索引的对象是面向PoJo的,这里的是Author,对应的文件是test/Author.cpm.xml.当然这里面的配置属性不止这么多,更多的属性见Configure属性。CompassConfiguration conf = new CompassConfiguration() .setSetting(CompassEnvironment.CONNECTION, "my/index/dir") .addResource(DublinCore.cmd.xml).addClass(Author.class);Compass compass = conf.buildCompass();这里我们CompassConfiguration会读取默认的在classpath中的compass.cfg.xml初始化,然后得到Compass对象,可能你会马上意思到这个Compass肯定对应于Hibenate中的SessionFactory,是的,这是一个重量级的对象,我们需要通过这个对象得到CompassSession,然后进行CRUD操作,CompassSession跟Hibernate中的Session一样是个lightweight对象。关于对Search domain的配置(Author.cpm.xml),大家可以查看cpm文件配置。在那里面主要是定义了那些properties是需要被索引的。<?xml version="1.0"?><!DOCTYPE compass-core-mapping PUBLIC "-//Compass/Compass Core Mapping DTD 1.0//EN" "http://www.opensymphony.com/compass/dtd/compass-core-mapping.dtd"><compass-core-mapping package="eg"> <class name="Author" alias="author"> <id name="id" /> <constant> <meta-data>type</meta-data> <meta-data-value>person</meta-data-value> <meta-data-value>author</meta-data-value> </constant> <property name="name"> <meta-data>name</meta-data> <meta-data>authorName</meta-data> </property> <property name="birthday"> <meta-data>birthday</meta-data> </property> <component name="books" ref-alias="book" /> <!-- can be a reference instead of component <reference name="books" ref-alias="book" /> --> </class> <class name="Book" alias="book"> ... </class></compass-core-mapping>2. 索引文件结构---[index dir]/index | |-- [subIndex1] | | | |--- segments | |--- [segment1] | |--- [segment2] | |-- [subIndex2] | | | |--- segments | |--- [segment1] | |--- [segment2] | |--- [segment3] |...基本上是一个search domain放到一个subIndex文件夹中,更确切的说是相同alias name的search domain放到相同的sub index folder中。3. Compass中的操作通过CompassSession我们可以进行save,delete, get,load。假如我们有两个domain Object,Author 和 Book,假如我们想要query Book的话要怎样做呢? 我们需要使用alias(这个属性定义在cmp文件中),通过CompassQueryBuilder去构造CompassQuery, CompassQueryBuilder非常灵活,非常像Hibernate的Criteria查询。具体的sample请看 Working with objects CompassHits hits = session.createQueryBuilder() .queryString("+name:jack +familyName:london") .setAnalyzer("an1") // use a different analyzer .toQuery() .addSort("familyName", CompassQuery.SortPropertyType.STRING) .addSort("birthdate", CompassQuery.SortPropertyType.INT) .hits();4. CompassGps and CompassGpsDeviceCompassGps像是一个Service,他需要在application startup时启动服务, application shutdown停止服务,CompassGpsDevice不能独立的存在,他需要依赖CompassGps, CompassGps为CompassGpsDevice提供Compass对象,他们一起为程序提供Index的实时更新。 Compass整合Hibernate 等等 persitance framework的代码就在CompassGpsDevice里,你需要提供不同的Device,如HibernateDevice, JDODevice。你也可以实现自己的Device, CompassGpsDevice会把domain object的更新事件通过CompassGps去通知Compass去更新索引文件,这样就是可以实时更新index了。有兴趣的话可以看看Hibernate3GpsDevice的registerEventsForHibernate31()方法,他给Hibernate的save,delete,update操作增加listener。当然我们可以使用aop自己去实现这块。CompassGps and CompassGpsDevice Compass compass = ... // configure compassCompassGps gps = new SingleCompassGps(compass);CompassGpsDevice device1 = ... // configure the first devicedevice1.setName("device1");gps.addDevice(device1);CompassGpsDevice device2 = ... // configure the second devicedevice2.setName("device2");gps.addDevice(device2);gps.start();........//on application shutdowngps.stop();5. 整合Spring,Hibenate在Compass的lib里面就有非常好的一个sample了(petclinic),里面有对Spring,Hibenate的整合,其实对spring来说也就是通过ioc把CompassGps 和 Compass定义好。CompassGps主要负责re-index和index实时更新, Compass主要提供了自定义Search部分的入口(CompassTemplate)。Spring提供了对Compass的DAO的整合,在CompassDaoSupport 中拿到CompassTemplate,这个跟spring对hibernatedao的支持是一致的。public class LibraryCompassDao extends CompassDaoSupport { public int getNumberOfHits(final String query) { Integer numberOfHits = (Integer)getCompassTemplate().execute( new CompassCallback() { public Object doInCompass(CompassSession session) { CompassHits hits = session.find(query); return new Integer(hits.getLength()); } } ); } return numberOfHits.intValue();}<beans> <bean id="libraryCompass" class="LibraryCompassDao"> <property name="compass"> <ref local="compass" /> </property> </bean></beans> <!-- COMPASS START --> <bean id="compass" class="org.compass.spring.LocalCompassBean"> <property name="resourceLocations"> <list> <value>classpath:org/compass/sample/petclinic/petclinic.cmd.xml</value> <value>classpath:petclinic.cpm.xml</value> </list> </property> <property name="compassSettings"> <props> <prop key="compass.engine.connection">file://${user.home}/compass/petclinic</prop> <prop key="compass.transaction.factory">org.compass.spring.transaction.SpringSyncTransactionFactory</prop> </props> </property> <property name="transactionManager"> <ref local="transactionManager" /> </property> </bean> <bean id="hibernateGpsDevice" class="org.compass.spring.device.hibernate.SpringHibernate3GpsDevice"> <property name="name"><value>hibernateDevice</value></property> <property name="sessionFactory"><ref local="sessionFactory" /></property> </bean> <bean id="compassGps" class="org.compass.gps.impl.SingleCompassGps" init-method="start" destroy-method="stop"> <property name="compass"><ref bean="compass" /></property> <property name="gpsDevices"> <list> <ref local="hibernateGpsDevice" /> </list> </property> </bean> <!-- COMPASS END --> <!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory"><ref local="sessionFactory"/></property> </bean><!----------------------------一下是对anototion的配置。--> <bean id="annotationConfiguration" class="org.compass.annotations.config.CompassAnnotationsConfiguration"> </bean> <!-- 核心Compass Bean,search及index时使用 --> <bean id="compass" class="org.compass.spring.LocalCompassBean"> <!-- anontaition式设置 --> <property name="classMappings"> <list> <value>com.dengyin.compass.sample.domain.Book</value> </list> </property> <property name="compassConfiguration" ref="annotationConfiguration"/> <!-- xml 文件式设置 <property name="resourceLocations"> <list> <value>classpath:compass-springside.cmd.xml</value> <value>classpath:compass-springside.cpm.xml</value> </list> </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的GPS绑定,在index时使用--> <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</value> </property> <property name="sessionFactory" ref="sessionFactory"/> </bean> </list> </property> </bean>ok! 相信你对Compass有一定的了解了。 thanksCompass: http://www.opensymphony.com/compass/Compass文档:http://www.opensymphony.com/compass/content/documentation.htmltrac:http://www.writely.com/View.aspx?docid=ajgd3tgv958v_0fmhxk9 |
|
急。。。你好 软件技术
chris(游客)发表评论于2007/1/23 15:01:14 |
我使用COMPASS时给数据库建索引抱的异常,怎么调也不行,难道是因为我使用的SQLSERVER2000,方言错误??帮帮我
[main][ERROR] 2007-01-26 14:46 org.compass.gps.device.jdbc.ResultSetJdbcGpsDevice - Failed to index databasejava.lang.ClassCastException at org.compass.gps.device.jdbc.dialect.DefaultJdbcDialect.getLong(DefaultJdbcDialect.java:58) at org.compass.gps.device.jdbc.dialect.DefaultJdbcDialect.getVersion(DefaultJdbcDialect.java:105) at org.compass.gps.device.jdbc.ResultSetRowMarshallHelper.marshallVersionsIfNeeded(ResultSetRowMarshallHelper.java:158) at org.compass.gps.device.jdbc.ResultSetRowMarshallHelper.marshallResultSet(ResultSetRowMarshallHelper.java:116) at org.compass.gps.device.jdbc.ResultSetJdbcGpsDevice.processRowValue(ResultSetJdbcGpsDevice.java:255) at org.compass.gps.device.jdbc.AbstractJdbcGpsDevice.processRow(AbstractJdbcGpsDevice.java:211) at org.compass.gps.device.jdbc.AbstractJdbcGpsDevice.processResultSet(AbstractJdbcGpsDevice.java:190) at org.compass.gps.device.jdbc.AbstractJdbcGpsDevice.doIndex(AbstractJdbcGpsDevice.java:155) at org.compass.gps.device.jdbc.ResultSetJdbcGpsDevice.doIndex(ResultSetJdbcGpsDevice.java:205) at org.compass.gps.device.AbstractGpsDevice$1.doInCompassWithoutResult(AbstractGpsDevice.java:90) at org.compass.core.CompassCallbackWithoutResult.doInCompass(CompassCallbackWithoutResult.java:29) at org.compass.core.CompassTemplate.execute(CompassTemplate.java:134) at org.compass.gps.impl.SingleCompassGps.executeForIndex(SingleCompassGps.java:149) at org.compass.gps.device.AbstractGpsDevice.index(AbstractGpsDevice.java:88) at org.compass.spring.device.SpringSyncTransactionGpsDeviceWrapper.index(SpringSyncTransactionGpsDeviceWrapper.java:86) at org.compass.gps.impl.SingleCompassGps$1.buildIndexIfNeeded(SingleCompassGps.java:121) at org.compass.core.lucene.engine.manager.DefaultLuceneSearchEngineIndexManager$1.firstStep(DefaultLuceneSearchEngineIndexManager.java:186) at org.compass.core.lucene.engine.manager.DefaultLuceneSearchEngineIndexManager.operate(DefaultLuceneSearchEngineIndexManager.java:130) at org.compass.core.lucene.engine.manager.DefaultLuceneSearchEngineIndexManager.replaceIndex(DefaultLuceneSearchEngineIndexManager.java:184) at org.compass.core.impl.DefaultCompass$TransactionalSearchEngineIndexManager$6.doInCompassWithoutResult(DefaultCompass.java:325) at org.compass.core.CompassCallbackWithoutResult.doInCompass(CompassCallbackWithoutResult.java:29) at org.compass.core.CompassTemplate.execute(CompassTemplate.java:134) at org.compass.core.CompassTemplate.execute(CompassTemplate.java:117) at org.compass.core.impl.DefaultCompass$TransactionalSearchEngineIndexManager.replaceIndex(DefaultCompass.java:323) at org.compass.core.lucene.engine.manager.ScheduledLuceneSearchEngineIndexManager.replaceIndex(ScheduledLuceneSearchEngineIndexManager.java:119) at org.compass.gps.impl.SingleCompassGps.doIndex(SingleCompassGps.java:116) at org.compass.gps.impl.AbstractCompassGps.index(AbstractCompassGps.java:106) at compasssamples.testArticle.performIndex(testArticle.java:95) at compasssamples.testArticle.testInsertArticle(testArticle.java:47) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:324) at junit.framework.TestCase.runTest(TestCase.java:154) at junit.framework.TestCase.runBare(TestCase.java:127) at junit.framework.TestResult$1.protect(TestResult.java:106) at junit.framework.TestResult.runProtected(TestResult.java:124) at junit.framework.TestResult.run(TestResult.java:109) at junit.framework.TestCase.run(TestCase.java:118) at junit.framework.TestSuite.runTest(TestSuite.java:208) at junit.framework.TestSuite.run(TestSuite.java:203) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196) |
|
» 1 »
|