`
weicong0468
  • 浏览: 8697 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Compass入门及其与Spring、iBatis的整合

阅读更多
本文是Compass的入门指引,通过实例介绍了Compass与iBatis、Spring的整合,适合不了解Compass的读者,但要求读者了解Lucene、Spring和iBatis,写过一些简单的应用。
文中使用的软件包:



什么是Compass
Compass是一个Java搜索框架。它封装了Lucene,增加了一些Lucene不支持的特性(例如实时更新索引),支持各种数据(Java对象、xml、json)到索引的映射,支持各种数据源(JDBC, Hibernate, iBatis)。



图解(看得烦的直接跳过看下面的例子吧):
• Compass - 一般在程序启动时建立并被整个程序共享,主要用于建立CompassSession并通过其管理索引数据。
• CompassSession - 用于处理数据的session。
• CompassTransaction - 手动进行事务管理,如果不使用,Compass会自动管理事务。
• CompassTemplate - 将session和transaction透明化。
• 数据到索引的各种映射 - OSEM, XSEM, JSEM, RSEM。支持通过程序、XML、JSON进行配置。
• CompassGps - Gps的核心模块,管理GpsDevice,有两种实现:SingleCompassGps和DualCompassGps。
• CompassGpsDevice - 处理各种数据源到索引的操作:JDBC, Hibernate, iBatis等。不能独立使用而必须融合到CompassGps中。

与Spring、iBatis的整合
建索引
1、假设Spring + iBatis的框架已经搭建好。

2、配置Domain的OSEM
Java代码 
1. @Searchable(alias="user")  
2. public class User {  
3.  
4.   @SearchableId 
5.   private int id;  
6.  
7.   @SearchableProperty(index=Index.ANALYZED, store=Store.YES)  
8.   private String name; // 姓名  
9.  
10.   @SearchableProperty(index=Index.NOT_ANALYZED, store=Store.YES)  
11.   private String gender; // 性别  
12.  
13.   @SearchableProperty(index=Index.NOT_ANALYZED, store=Store.YES)  
14.   private int age; // 年龄  
15.  
16.   public User() {  
17.   }  
18.  
19.   public User(String name, String gender, int age) {  
20.     setName(name);  
21.     setGender(gender);  
22.     setAge(age);  
23.   }  
24.  
25.   public int getId() {  
26.     return id;  
27.   }  
28.  
29.   public void setId(int id) {  
30.     this.id = id;  
31.   }  
32.  
33.   public String getName() {  
34.     return name;  
35.   }  
36.  
37.   public void setName(String name) {  
38.     this.name = name;  
39.   }  
40.  
41.   public String getGender() {  
42.     return gender;  
43.   }  
44.  
45.   public void setGender(String gender) {  
46.     this.gender = gender;  
47.   }  
48.  
49.   public int getAge() {  
50.     return age;  
51.   }  
52.  
53.   public void setAge(int age) {  
54.     this.age = age;  
55.   }  
56.  
57. } 

其实就是加几个Annotation而已。看到Index.ANALYZED、Store.YES这些东西,用过Lucene的应该大概都明白了吧。

• @Searchable - 指明该类可被映射至索引,alias参数是这一类索引对象的别名。
• @SearchableId - 索引对象的id,在同一类索引对象(同一个alias)中唯一标识一个对象。
• @SearchableProperty - 指示一个类属性如何被索引,index和store参数类似Lucene。
3、建立LocalCompassBean,配置索引文件存放路径和进行映射的domain。
Xml代码 
1. <bean id="compass" class="org.compass.spring.LocalCompassBean"> 
2.   <property name="compassSettings"> 
3.     <props> 
4.       <!-- 索引文件保存路径 --> 
5.       <prop key="compass.engine.connection">/home/index/compasstest</prop> 
6.     </props> 
7.   </property> 
8.   <property name="classMappings"> <!-- 进行映射的domain --> 
9.     <list> 
10.       <value>ren.domain.User</value> 
11.       <value>ren.domain.Book</value> 
12.     </list> 
13.   </property> 
14. </bean> 

4、建立SqlMapClientGpsDevice,配置iBatis的sqlMapClient和获取数据进行索引的SQL语句id。
Xml代码 
1. <bean id="ibatisGpsDevice" class="org.compass.gps.device.ibatis.SqlMapClientGpsDevice"> 
2.   <property name="name" value="ibatis" /> 
3.   <property name="sqlMapClient"> 
4.     <ref bean="sqlMapClient" /> <!-- 引用项目中已经定义的ibatis的sqlMapClient --> 
5.   </property> 
6.   <property name="selectStatementsIds"> <!-- 对这些SQL查询的结果进行索引 --> 
7.     <list> 
8.       <value>user.getAllUsers</value> 
9.       <value>book.getAllBooks</value> 
10.     </list> 
11.   </property> 
12. </bean> 

5、建立CompassGps(SingleCompassGps或DualCompassGps),引用前面的compass和device。
Xml代码 
1. <bean id="compassGps" class="org.compass.gps.impl.SingleCompassGps" 
2.   init-method="start" destroy-method="stop"> 
3.   <property name="compass" ref="compass" /> 
4.   <property name="gpsDevices"> 
5.     <list> 
6.       <ref local="ibatisGpsDevice"/> 
7.     </list> 
8.   </property> 
9. </bean> 

6、最后,直接调用CompassGps.index()方法建立索引。
Java代码 
1. @Component 
2. @Qualifier("indexBuilder")  
3. public class IndexBuilder {  
4.  
5.   @Autowired 
6.   @Qualifier("compassGps")  
7.   private CompassGps compassGps;  
8.     
9.   public void buildIndex() {  
10.     compassGps.index(); // 一行代码搞定  
11.   }  
12.  
13. } 

查索引
1、建立CompassTemplate,引用LocalCompassBean。
Xml代码 
1. <bean id="compassTemplate" class="org.compass.core.CompassTemplate"> 
2.   <property name="compass"> 
3.     <ref bean="compass" /> 
4.   </property> 
5. </bean> 
 

2、使用CompassTemplate.execute(CompassCallback<T>)进行查询。
Java代码 
1. @Component 
2. @Qualifier("indexSearcher")  
3. public class IndexSearcher {  
4.     
5.   @Autowired 
6.   @Qualifier("compassTemplate")  
7.   private CompassTemplate compassTemplate;  
8.     
9.   /** 
10.    * 搜索用户 
11.    */ 
12.   public List<User> searchUser(final String name, final String gender, final int age) {  
13.     return compassTemplate.execute(new CompassCallback<List<User>>() {  
14.       public List<User> doInCompass(CompassSession session) throws CompassException {  
15.         CompassQueryBuilder builder = session.queryBuilder();  
16.         String queryString = "";  
17.         if (!StringUtils.isBlank(name)) {  
18.           queryString += "and user.name:" + name;  
19.         }  
20.         if (!StringUtils.isBlank(gender)) {  
21.           queryString += "and user.gender:" + gender;  
22.         }  
23.         if (age > 0) {  
24.           queryString += "and user.age:" + age;  
25.         }  
26.         CompassQuery query = builder.queryString(queryString).toQuery();  
27.         query.addSort("user.age", SortPropertyType.INT, SortDirection.REVERSE);  
28.         CompassHits hits = query.hits();  
29.         List<User> list = new ArrayList<User>();  
30.         for (CompassHit hit : hits) {  
31.           list.add((User)hit.data());  
32.         }  
33.         return list;  
34.       }  
35.     });  
36.   }  
37.  
38. } 

拼查询字符串这里写得比较累赘,小朋友不要学~

与Lucene的比较
1、Compass有比Lucene更易用的API(废话,封装了Lucene嘛),例如支持直接更新记录(因为resource类似数据库记录,含有主键)。像上面的建索引过程,如果用Lucene,肯定得写很多Java代码。

2、支持整合各种ORM框架和Spring,减少了代码量。例如上面例子中整合iBatis,直接几行配置就搞定了。

3、效率问题?感觉Lucene的API用起来老是不顺手,Compass这样封装虽然方便了,但有些担心会不会降低了性能,于是做了个简单的测试,分别索引4万条记录,结果是
         Compass: 12203 ms.
         Lucene: 9797 ms.
     Compass比Lucene慢了大约25%,当然这个测试十分粗略,结果仅供参考。

经验总结
1、对多个表建索引后进行搜索,在添加排序条件时,如果不指定SortPropertyType,那么在没有指定converter的字段上排序时会抛Exception:
    java.lang.RuntimeException: field "gender" does not appear to be indexed
    但如果只对单个表建索引,不会有这个问题。应该是Compass的一个bug,不知道新版本有没有解决。

2、最好自己封装排序字段和分页。

3、总结,Compass比较适用于逻辑不太复杂的应用,会比Lucene少写很多代码。但如果需要一些较为特殊的需求,或者对效率要求比较高,还是用Lucene吧。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics