Compass是基于Lucene的更高層的抽象,假如你正打算做關(guān)于搜索方面的模塊的話,那我建議你使用Compass,他提供了可配置方案,而且比Lucene更加容易使用。如果你的系統(tǒng)中使用Spring, Hibernate,JDO, IBatis。。。 Compass是最好的選擇,他能夠非常方便的集成到現(xiàn)有系統(tǒng)中去。
1. Compass的framework的系統(tǒng)結(jié)構(gòu)。
感覺Compass的代碼的結(jié)構(gòu)簡直就是剽竊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的思想轉(zhuǎn)移到Compass上?,F(xiàn)在讓我們看看他們之間的相似吧。
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總的配置文件,其中定義了索引文件存儲的位置(這里是用文件系統(tǒng),Compass有多種選擇,你也可以選數(shù)據(jù)庫或其他),Compass索引的對象是面向PoJo的,這里的是Author,對應(yīng)的文件是test/Author.cpm.xml.
當(dāng)然這里面的配置屬性不止這么多,更多的屬性見Configure屬性。
CompassConfiguration conf = new CompassConfiguration()
.setSetting(CompassEnvironment.CONNECTION, "my/index/dir")
.addResource(DublinCore.cmd.xml).addClass(Author.class);
Compass compass = conf.buildCompass();
這里我們CompassConfiguration會讀取默認(rèn)的在classpath中的compass.cfg.xml初始化,然后得到Compass對象,可能你會馬上意思到這個Compass肯定對應(yīng)于Hibenate中的SessionFactory,是的,這是一個重量級的對象,
我們需要通過這個對象得到CompassSession,然后進行CRUD操作,CompassSession跟Hibernate中的Session一樣是個lightweight對象。關(guān)于對Search domain的配置(Author.cpm.xml),大家可以查看cpm文件配置。在那里面
主要是定義了那些properties是需要被索引的。
<?xml version="1.0"?>
<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. 索引文件結(jié)構(gòu)
---[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去構(gòu)造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 CompassGpsDevice
CompassGps像是一個Service,他需要在application startup時啟動服務(wù), applicationshutdown停止服務(wù),CompassGpsDevice不能獨立的存在,他需要依賴CompassGps,CompassGps為CompassGpsDevice提供
Compass對象,他們一起為程序提供Index的實時更新。Compass整合Hibernate 等等 persitanceframework的代碼就在CompassGpsDevice里,你需要提供不同的Device,如HibernateDevice,JDODevice。你也
可以實現(xiàn)自己的Device, CompassGpsDevice會把domain object的更新事件通過CompassGps去通知Compass去更新索引文件,這樣就是可以實時更新index了。有興趣的話可以看看Hibernate3GpsDevice的
registerEventsForHibernate31()方法,他給Hibernate的save,delete,update操作增加listener。當(dāng)然我們可以使用aop自己去實現(xiàn)這塊。CompassGps and CompassGpsDevice
Compass compass = ... // configure compass
CompassGps gps = new SingleCompassGps(compass);
CompassGpsDevice device1 = ... // configure the first device
device1.setName("device1");
gps.addDevice(device1);
CompassGpsDevice device2 = ... // configure the second device
device2.setName("device2");
gps.addDevice(device2);
gps.start();
....
....
//on application shutdown
gps.stop();
5. 整合Spring,Hibenate
在Compass的lib里面就有非常好的一個sample了(petclinic),里面有對Spring,Hibenate的整合,其實對spring來說也就是通過ioc把CompassGps 和 Compass定義好。CompassGps主要負(fù)責(zé)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>
<propkey="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式設(shè)置 -->
<property name="classMappings">
<list>
<value>com.dengyin.compass.sample.domain.Book</value>
</list>
</property>
<property name="compassConfiguration" ref="annotationConfiguration"/>
<!-- xml 文件式設(shè)置
<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有一定的了解了。 thanks
Compass: http://www.opensymphony.com/compass/
Compass文檔:http://www.opensymphony.com/compass/content/documentation.html