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

Compass是一个Java搜索框架。它封装了Lucene,增加了一些Lucene不支持的特性(例如实时更新索引),支持各种数据(Java对象、xml、json)到索引的映射,支持各种数据源(JDBC, Hibernate, 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的应该大概都明白了吧。
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;
}
});
}
} 拼查询字符串这里写得比较累赘,小朋友不要学~
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
如:对于sql语句order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by "111", 如果传入的值是id,则解析成的sql为order by "id"。