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

  • 开始之前
  • 什么是Compass
  • 与Spring、iBatis的整合
  • 与Lucene的比较
  • 经验总结
  • 相关资源

开始之前

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

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

什么是Compass

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

Compass入门及其与Spring、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

@Searchable
(alias=
"user"
)  



public
 
class
 User {  



  


  @SearchableId
  



  private
 
int
 id;  



  


  @SearchableProperty
(index=Index.ANALYZED, store=Store.YES)  



  private
 String name; 
// 姓名
  



  


  @SearchableProperty
(index=Index.NOT_ANALYZED, store=Store.YES)  



  private
 String gender; 
// 性别
  



  


  @SearchableProperty
(index=Index.NOT_ANALYZED, store=Store.YES)  



  private
 
int
 age; 
// 年龄
  



  


  public
 User() {  



  }  


  


  public
 User(String name, String gender, 
int
 age) {  



    setName(name);  


    setGender(gender);  


    setAge(age);  


  }  


  


  public
 
int
 getId() {  



    return
 id;  



  }  


  


  public
 
void
 setId(
int
 id) {  



    this
.id = id;  



  }  


  


  public
 String getName() {  



    return
 name;  



  }  


  


  public
 
void
 setName(String name) {  



    this
.name = name;  



  }  


  


  public
 String getGender() {  



    return
 gender;  



  }  


  


  public
 
void
 setGender(String gender) {  



    this
.gender = gender;  



  }  


  


  public
 
int
 getAge() {  



    return
 age;  



  }  


  


  public
 
void
 setAge(
int
 age) {  



    this
.age = age;  



  }  


  


}  

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

  • @Searchable - 指明该类可被映射至索引,alias参数是这一类索引对象的别名。
  • @SearchableId - 索引对象的id,在同一类索引对象(同一个alias)中唯一标识一个对象。
  • @SearchableProperty - 指示一个类属性如何被索引,index和store参数类似Lucene。

3、建立LocalCompassBean,配置索引文件存放路径和进行映射的domain。

@Component
  



@Qualifier
(
"indexBuilder"
)  



public
 
class
 IndexBuilder {  



  


  @Autowired
  



  @Qualifier
(
"compassGps"
)  



  private
 CompassGps compassGps;  



    


  public
 
void
 buildIndex() {  



    compassGps.index(); // 一行代码搞定
  



  }  


  


}  

查索引

1、建立CompassTemplate,引用LocalCompassBean。

@Component
  



@Qualifier
(
"indexSearcher"
)  



public
 
class
 IndexSearcher {  



    


  @Autowired
  



  @Qualifier
(
"compassTemplate"
)  



  private
 CompassTemplate compassTemplate;  



    


  /**
 


   * 搜索用户
 


   */
  



  public
 List<User> searchUser(
final
 String name, 
final
 String gender, 
final
 
int
 age) {  



    return
 compassTemplate.execute(
new
 CompassCallback<List<User>>() {  



      public
 List<User> doInCompass(CompassSession session) 
throws
 CompassException {  



        CompassQueryBuilder builder = session.queryBuilder();  


        String queryString = ""
;  



        if
 (!StringUtils.isBlank(name)) {  



          queryString += "and user.name:"
 + name;  



        }  


        if
 (!StringUtils.isBlank(gender)) {  



          queryString += "and user.gender:"
 + gender;  



        }  


        if
 (age > 
0
) {  



          queryString += "and user.age:"
 + age;  



        }  


        CompassQuery query = builder.queryString(queryString).toQuery();  


        query.addSort("user.age"
, SortPropertyType.INT, SortDirection.REVERSE);  



        CompassHits hits = query.hits();  


        List<User> list = new
 ArrayList<User>();  



        for
 (CompassHit hit : hits) {  



          list.add((User)hit.data());  


        }  


        return
 list;  



      }  


    });  


  }  


  


}  

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

与Lucene的比较

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

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

3、效率问题?感觉Lucene的API用起来老是不顺手,Compass这样封装虽然方便了,但有些担心会不会降低了性能,于是做了个简单的测试,分别索引4万条记录,结果是

Compass:12203ms.

         Lucene: 9797 ms.

     Compass比Lucene慢了大约25%,当然这个测试十分粗略,结果仅供参考。

经验总结

1、对多个表建索引后进行搜索,在添加排序条件时,如果不指定SortPropertyType,那么在没有指定converter的字段上排序时会抛Exception:

java.lang.RuntimeException:field"gender"doesnotappeartobeindexed

    但如果只对单个表建索引,不会有这个问题。应该是Compass的一个bug,不知道新版本有没有解决。

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

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

相关资源

Compass入门指南:http://www.yeeach.com/2008/03/23/compass-%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97/

全文检索的基本原理:http://blog.csdn.net/forfuture1978/archive/2009/10/22/4711308.aspx

大型网站的Lucene应用:http://www.luanxiang.org/blog/archives/605.html

相关推荐