接触Compass有比较长的一段时间了,以前的应用都是基于XML配置文件的XSEM搜索的,比如一个学生选修多门学科,如“语文”,如果搜索哪些学生选修“语文”学科时,基于配置文件的搜索通常是先搜索出“语文”科目的id,然后再搜索学生中含该id的记录,非常的不方便。最近做项目时发现Compass提供了基于对象方式的搜索,但苦于网上关于这方面的内容介绍的要么太少,要么太浅。Compass的官方手册也介绍的不详尽。于是花费了比较长的时间自已摸索,光一个小问题就困挠了一周才得到结果,呵呵,为了方便同样有这方面需要的朋友,特别整理文档。本文的环境是:compass 2.2,如果朋友们对本文的描述不理解,可以加我的MSN沟通,xunmeng_hot@hotmail.com,希望不致于误人子弟。呵呵。
我的demo:一个学生(Student)有一个HomeTown,每个学生可以选修多门学科。
实体类如下:
Student:
@Searchable
@SearchAnalyzer(name = "student", type = AnalyzerType.Standard)
public class Student {
private int id;
private String name;
private HomeTown homeTown;
private List<Course> courses;
@SearchableId
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@SearchableProperty(name = "studentName",index=Index.NOT_ANALYZED,managedIdIndex = ManagedIdIndex.NOT_ANALYZED)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@SearchableComponent(refAlias = "HomeTown")
public HomeTown getHomeTown() {
return homeTown;
}
public void setHomeTown(HomeTown homeTown) {
this.homeTown = homeTown;
}
@SearchableComponent(refAlias = "Course")
public List<Course> getCourses() {
return courses;
}
public void setCourses(List<Course> courses) {
this.courses = courses;
}
}
HomeTown
@Searchable
@SearchAnalyzer(name = "homeTown", type = AnalyzerType.Standard)
public class HomeTown {
private int id;
private String city;
@SearchableId
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@SearchableProperty(name = "homeTownName",index=Index.NOT_ANALYZED,managedIdIndex = ManagedIdIndex.NOT_ANALYZED)
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
Course:
@Searchable
@SearchAnalyzer(name = "course", type = AnalyzerType.Standard)
public class Course {
private int id;
private String name;
@SearchableId
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@SearchableProperty(name = "courseName",index=Index.NOT_ANALYZED,managedIdIndex = ManagedIdIndex.NOT_ANALYZED)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
同时给出它们的Hibernate配置文件:
//Student
<hibernate-mapping default-lazy="false">
<class name="org.wangwanbao.compass.osem.entity.Student" table="student">
<id name="id" type="int">
<column name="id" />
<generator class="native" />
</id>
<property name="name" column="name" type="string" />
<many-to-one name="homeTown" column="hometown_id" cascade="all"
class="org.wangwanbao.compass.osem.entity.HomeTown" />
<list name="courses"
table="courses" cascade="all" lazy="false">
<key column="stuent_id" not-null="true" />
<index column="IDX" />
<one-to-many
class="org.wangwanbao.compass.osem.entity.Course" />
</list>
</class>
</hibernate-mapping>
//HomeTown
<hibernate-mapping default-lazy="false">
<class name="org.wangwanbao.compass.osem.entity.HomeTown" table="hometown">
<id name="id" type="int">
<column name="id" />
<generator class="native" />
</id>
<property name="city" column="city" type="string" />
</class>
</hibernate-mapping>
//Course
<hibernate-mapping default-lazy="false">
<class name="org.wangwanbao.compass.osem.entity.Course" table="course">
<id name="id" type="int">
<column name="id" />
<generator class="native" />
</id>
<property name="name" column="name" type="string" />
</class>
</hibernate-mapping>
Mysql数据库脚本及测试数据
CREATE TABLE `course` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(255) default NULL,
`stuent_id` int(11) NOT NULL,
`IDX` int(11) default NULL,
PRIMARY KEY (`id`),
KEY `FKAF42E01BFB3BE844` (`stuent_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=7 ;
--
-- 导出表中的数据 `course`
--
INSERT INTO `course` VALUES (3, '语文', 4, 0);
INSERT INTO `course` VALUES (4, '物理', 4, 1);
INSERT INTO `course` VALUES (5, '数学', 5, 0);
INSERT INTO `course` VALUES (6, '化学', 5, 1);
-- --------------------------------------------------------
--
-- 表的结构 `hometown`
--
CREATE TABLE `hometown` (
`id` int(11) NOT NULL auto_increment,
`city` varchar(255) default NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;
--
-- 导出表中的数据 `hometown`
--
INSERT INTO `hometown` VALUES (3, '九江');
INSERT INTO `hometown` VALUES (4, '南昌');
-- --------------------------------------------------------
--
-- 表的结构 `student`
--
CREATE TABLE `student` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(255) default NULL,
`hometown_id` int(11) default NULL,
PRIMARY KEY (`id`),
KEY `FK8FFE823B1AA8EF14` (`hometown_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=6 ;
--
-- 导出表中的数据 `student`
--
INSERT INTO `student` VALUES (4, 'wangwanbao', 3);
INSERT INTO `student` VALUES (5, 'xunmeng_hot@hotmail.com', 4);
OK了,准备工作都做好了,下面开如Compass之旅。当然,首先需要创建索引。我们需要先构建一个Compass类。
采用工厂方法创建
public class CompassSessionFactory {
public static Compass getCompass() {
CompassConfiguration conf = new CompassConfiguration()
.configure("/student_compass.cfg.xml");
conf.getSettings().setSetting(CompassEnvironment.Cache.FirstLevel.TYPE,
NullFirstLevelCache.class.getName());
conf.getSettings().setBooleanSetting(CompassEnvironment.DEBUG, true);
conf.addClass(Student.class).addClass(HomeTown.class).addClass(
Course.class);
return (InternalCompass) conf.buildCompass();
}
}
大家注意到代码中有一个配置文件,这个配置文件中可以设置索引存放的路径及一些其它参数。文件如下:
<compass-core-config xmlns="http://www.compass-project.org/schema/core-config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.compass-project.org/schema/core-config http://www.compass-project.org/schema/compass-core-config-2.2.xsd">
<compass name="default">
<connection>
<file path="f:/student"/>
</connection>
<transaction>
<processors>
<readCommitted transLog="ram://" />
</processors>
</transaction>
<cache>
<firstLevel type="org.compass.core.cache.first.NullFirstLevelCache" />
</cache>
<searchEngine useCompoundFile="true">
<optimizer schedule="false" />
</searchEngine>
</compass>
</compass-core-config>
配置Spring的工厂Bean
<bean id="compass" class="org.wangwanbao.compass.osem.compass.CompassSessionFactory" factory-method="getCompass"/>
创建索引需要CompassGps,这里配置一下:
<bean id="hibernateGpsDevice"
class="org.compass.gps.device.hibernate.HibernateGpsDevice">
<property name="name">
<value>hibernateDevice</value>
</property>
<property name="sessionFactory">
<ref bean="mySessionFactory" />
</property>
<property name="nativeExtractor">
<bean
class="org.compass.spring.device.hibernate.SpringNativeHibernateExtractor" />
</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>
<bean
class="org.compass.spring.device.SpringSyncTransactionGpsDeviceWrapper">
<property name="gpsDevice" ref="hibernateGpsDevice" />
</bean>
</list>
</property>
</bean>
Ok了,现在可以创建索引文件了。
public void index() {
StopWatch sw = new StopWatch();
sw.start();
compassGps.index();
sw.stop();
log.info("索引建立完毕,共花费时间:" + sw.getTime() / 1000 + "秒");
}
创建索引后进入我们的主要任务吧,构建一个搜索器,首先我们创建一个Request类,它是基于泛型的。代码:
public class SearchRequest {
Class entityClass;
String alias;
List<SearchField> fields;
public class SearchField {
String fieldName;
String fieldValue;
Occur fieldType;
public String getFieldName() {
return fieldName;
}
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
public String getFieldValue() {
return fieldValue;
}
public void setFieldValue(String fieldValue) {
this.fieldValue = fieldValue;
}
public Occur getFieldType() {
return fieldType;
}
public void setFieldType(Occur fieldType) {
this.fieldType = fieldType;
}
}
public Class getEntityClass() {
return entityClass;
}
public void setEntityClass(Class entityClass) {
this.entityClass = entityClass;
}
public String getAlias() {
return alias;
}
public void setAlias(String alias) {
this.alias = alias;
}
public List<SearchField> getFields() {
return fields;
}
public void setFields(List<SearchField> fields) {
this.fields = fields;
}
}
主要搜索类的代码:
public <T> List<T> searchByOSEM(SearchRequest sr){
CompassSession session = getCompass().openSession();
CompassTransaction tr = session.beginTransaction();
CompassQueryBuilder builder = session.queryBuilder();
CompassQueryBuilder.CompassBooleanQueryBuilder booleanQuery = builder
.bool();
List<SearchRequest.SearchField> searchFields = sr.getFields();
if(searchFields.size() <1)
return null;
for(SearchRequest.SearchField sf : searchFields){
if(Occur.MUST.equals(sf.getFieldType())){
booleanQuery.addMust(builder.term(sf.getFieldName(),sf.getFieldValue()));
}else if(Occur.SHOULD.equals(sf.getFieldType())){
booleanQuery.addShould(builder.term(sf.getFieldName(),sf.getFieldValue()));
}else if(Occur.MUST_NOT.equals(sf.getFieldType())){
booleanQuery.addMustNot(builder.term(sf.getFieldName(),sf.getFieldValue()));
}
}
CompassQuery compassQuery = booleanQuery.toQuery()
.setAliases(sr.getAlias());
CompassHits hits = compassQuery.hits();
CompassHit[] detachedHits = new CompassHit[0];
detachedHits = hits.detach().getHits();
return termSearchResults(sr.getEntityClass(), detachedHits);
}
最后我们来创建一个测试代码来,来看看是否能达到效果:
public void testSearch() {
CompassDaoImpl cd = (CompassDaoImpl) factory.getBean("compassDAO");
List<SearchRequest.SearchField> searchFields = new ArrayList<SearchRequest.SearchField>();
SearchRequest.SearchField s1 = new SearchRequest().new SearchField();
s1.setFieldName("Student.name");
s1.setFieldType(Occur.MUST);
s1.setFieldValue("wangwanbao");
SearchRequest.SearchField s2 = new SearchRequest().new SearchField();
s2.setFieldName("Student.courses.name");
s2.setFieldType(Occur.MUST);
s2.setFieldValue("语文");
searchFields.add(s1);
searchFields.add(s2);
SearchRequest sr = new SearchRequest();
sr.setAlias("Student");
sr.setEntityClass(Student.class);
sr.setFields(searchFields);
List<Student> students = cd.searchByOSEM(sr);
if(students.size() <1){
System.out.println("长度为0");
}else{
for(Student s : students){
System.out.println(s.getName() + "---" + s.getHomeTown().getCity());
}
}
}
控制台最后输出:wangwanbao---九江,测试成功!
应网友要求,给出例子的源代码。
分享到:
相关推荐
总的来说,构建基于Compass和Spring的搜索引擎涉及理解Compass的核心概念,如OSEM、配置方式和API,以及如何利用Spring的集成优势简化开发流程。通过这种方式,开发者可以快速、高效地实现一个功能完备的全文搜索...
因此,Compass是基于Lucene之上构建的,但其功能更为丰富和高级。一个形象的比喻是,Compass对于Lucene,就像Hibernate对于JDBC一样,它完全参照Hibernate的开发模式,极大地提升了搜索框架的易用性和功能性。 3. *...
Compass 是一个基于 Java 的搜索引擎框架,它充分利用了 Apache Lucene 的强大功能,并与流行的框架如 Hibernate 和 Spring 集成,使得在 Java 应用中集成全文搜索变得简单高效。该框架的主要目的是减少开发者的编码...
1. Compass Core:基础模块,提供事务管理和搜索引擎映射功能,如对象-搜索引擎映射(OSEM)。 2. Compass GPS:用于与不同数据源集成,如ORM框架,支持JDBC等。 3. Compass Spring:整合Spring框架,便于在Spring...
Compass依赖于顶级的Lucene搜索引擎,并与诸如Hibernate和Spring等流行框架相结合,为应用程序提供了从数据模型和数据源同步变化的搜索能力。此外,它还添加了两方面的特性:事务管理和快速更新优化。 Compass的...
Compass基于Lucene之上,类似于Hibernate之于JDBC的关系,提供了更高层次的封装,使得开发者能够更容易地集成搜索引擎到Java应用程序中。 - **OSEM**:OSEM (Object Search Engine Mapping) 是Compass提供的一个...
2. **对象-搜索引擎映射(OSEM)**:类似于Hibernate的对象-关系映射,Compress实现了对象-搜索引擎映射,允许开发者将Java对象直接映射到搜索索引中。这样,你可以直接操作业务对象,而无需关心底层的索引结构。 3...
Compass是为Java开发人员设计的一个高性能、高灵活性的搜索引擎库,旨在简化在应用中集成全文搜索功能的过程。它基于Lucene构建,提供了丰富的API和高度可定制性,允许开发者以最小的努力实现复杂的数据索引和查询。...
**Compass**是一个功能强大、高性能的对象/搜索引擎映射(OSEM)框架,它基于Java语言开发,提供了一个方便的方式来管理和查询索引数据。Compass的主要特点包括: - **搜索引擎抽象层**:提供了一套统一的接口来...
Java 3DMenu 界面源码 5个目标文件 内容索引:Java源码,窗体界面,3DMenu Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都...
Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码...
Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java...
Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java...
Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java...
Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码,文件操作,压缩包查看 Java zip压缩包查看程序,应用弹出文件选择框,选择ZIP格式的压缩文件,可以像Winrar软件一样查看压缩文件内部的文件及文件夹,源码...
Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码,文件操作,压缩包查看 Java zip压缩包查看程序,应用弹出文件选择框,选择ZIP格式的压缩文件,可以像Winrar软件一样查看压缩文件内部的文件及文件夹,源码...