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

Compass入门 及于spring和ibatis结合

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


开始之前

本文是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. }  
@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。

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 >   
  <bean id="compass" class="org.compass.spring.LocalCompassBean">
    <property name="compassSettings">
      <props>
        <!-- 索引文件保存路径 -->
        <prop key="compass.engine.connection">/home/index/compasstest</prop>
      </props>
    </property>
    <property name="classMappings"> <!-- 进行映射的domain -->
      <list>
        <value>ren.domain.User</value>
        <value>ren.domain.Book</value>
      </list>
    </property>
  </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 >   
  <bean id="ibatisGpsDevice" class="org.compass.gps.device.ibatis.SqlMapClientGpsDevice">
    <property name="name" value="ibatis" />
    <property name="sqlMapClient">
      <ref bean="sqlMapClient" /> <!-- 引用项目中已经定义的ibatis的sqlMapClient -->
    </property>
    <property name="selectStatementsIds"> <!-- 对这些SQL查询的结果进行索引 -->
      <list>
        <value>user.getAllUsers</value>
        <value>book.getAllBooks</value>
      </list>
    </property>
  </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 >   
  <bean id="compassGps" class="org.compass.gps.impl.SingleCompassGps"
    init-method="start" destroy-method="stop">
    <property name="compass" ref="compass" />
    <property name="gpsDevices">
      <list>
        <ref local="ibatisGpsDevice"/>
      </list>
    </property>
  </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. }  
@Component
@Qualifier("indexBuilder")
public class IndexBuilder {

  @Autowired
  @Qualifier("compassGps")
  private CompassGps compassGps;
  
  public void buildIndex() {
    compassGps.index(); // 一行代码搞定
  }

}

查索引

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 >   
  <bean id="compassTemplate" class="org.compass.core.CompassTemplate">
    <property name="compass">
      <ref bean="compass" />
    </property>
  </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. }  
@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: 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吧。

相关资源

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

写在后面

这篇文章是根据自己的一次演讲整理出来的,主要就是PPT内容 + 代码。演讲和写文章确实很不同,感觉很多地方还说不清楚,因为内容太多了吧,看来自己的书面组织能力还有待提高啊~

分享到:
评论

相关推荐

    compass+ibatis+spring+struts2整合开发

    compass+ibatis+spring+struts2整合开发compass+ibatis+spring+struts2整合开发compass+ibatis+spring+struts2整合开发compass+ibatis+spring+struts2整合开发

    compass_hibernate_spring2.zip

    标题“compass_hibernate_spring2.zip”提示我们这个压缩包可能包含了关于 Compass、Hibernate 和 Spring 三者结合使用的示例或教程。Compass 是一个全文搜索引擎,Hibernate 是一个流行的 Java ORM(对象关系映射)...

    基于Compass2.2与Spring 结合建立索引的实例

    ### 基于Compass2.2与Spring结合建立索引的实例 #### 一、Compass简介 Compass是一个开源的.NET和Java框架,它为应用程序提供了完整的文本搜索功能。该框架支持多种搜索引擎(如Elasticsearch, Solr等),使得开发...

    compass_hibernate_spring3.zip

    标题“compass_hibernate_spring3.zip”提示我们这个压缩包可能包含了关于 Compass、Hibernate 和 Spring 3 框架的整合教程或者示例代码。Compass 是一个全文搜索引擎库,它为 Java 应用提供了类似 Google 的搜索...

    compass_hibernate_spring.zip

    总之,Compass、Hibernate和Spring的整合是一个强大且实用的解决方案,它让Java应用在处理大量数据时依然能保持良好的性能和响应速度。通过理解并掌握这种整合方式,开发者能够更好地应对复杂的企业级应用场景。

    Compass全文检索系列之一:Compass入门

    1. **ORM集成**:Compass可以与流行的ORM框架如Hibernate、JPA、iBatis等进行集成,自动将数据库中的对象创建成索引,无需手动处理索引的创建和维护。 2. **动态索引更新**:当数据库中的数据发生变化时,Compass...

    compass入门指南

    ### Compass入门指南:深入理解与实战应用 #### 核心概念解析 **1.1 Annotation vs. XML配置文件** 在Compass中,开发者可以选择使用Annotation或XML配置文件来进行配置。这两种方式各有优劣: - **Annotation...

    整合compass2.0 spring hibernate示例源程序

    标题 "整合compass2.0 spring hibernate示例源程序" 提供了我们即将探讨的核心内容,即一个结合了Compass 2.0、Spring和Hibernate的集成示例。这个项目旨在展示如何在Java应用程序中有效地利用这三个强大的开源框架...

    compass的几个入门网页

    Compass与Sass的结合,使得CSS代码更加模块化,更易于维护和扩展,同时引入了变量、嵌套规则、混合、函数等功能,让CSS编程变得更为强大。 二、Compass的安装 在开始使用Compass之前,你需要确保已经安装了Ruby环境...

    STRUTS SPRING COMPASS 实例

    在IT行业中,STRUTS、SPRING和HIBERNATE是三个非常重要的开源框架,它们分别专注于MVC(模型-视图-控制器)架构、依赖注入以及对象关系映射。而COMPASS则是一个基于Lucene的搜索引擎库,用于增强Java应用的全文检索...

    COMPASS+spring构建自己的搜索引擎.pdf

    总的来说,构建基于Compass和Spring的搜索引擎涉及理解Compass的核心概念,如OSEM、配置方式和API,以及如何利用Spring的集成优势简化开发流程。通过这种方式,开发者可以快速、高效地实现一个功能完备的全文搜索...

    Spring ,JPA,Compass使用注解开发的博客站内搜索

    标题 "Spring ,JPA,Compass使用注解开发的博客站内搜索" 涉及的是在Java开发环境中,利用Spring框架、Java Persistence API (JPA) 和 Compass搜索引擎来实现一个博客系统的站内搜索功能。这是一项关键的技术,因为...

    compass-2.2.0+hibernate-3.2+struts-2.1.8.1+spring-framework-2.5.4

    标题 "compass-2.2.0+hibernate-3.2+struts-2.1.8.1+spring-framework-2.5.4" 指的是一个集成开发环境,它结合了四个关键的技术组件:Compass、Hibernate、Struts 2 和 Spring Framework,这些都是Java Web开发中的...

    struts2+spring2.5+hibernate3.26+compass2.1搜索引擎简单实现(无jar包)

    Struts2、Spring、Hibernate和Compass是Java Web开发中常用的四大框架,它们各自负责不同的职责,协同工作可以构建高效、灵活的企业级应用。这里我们主要讨论如何将这些技术结合在一起,实现一个简单的搜索引擎功能...

    struts2 hibernate spring compass全文检索

    Struts2、Hibernate、Spring 和 Compass 是Java Web开发中四个重要的框架和技术,它们共同构建了一个强大的企业级应用架构。在本项目中,开发者利用SSH2(即Struts2、Hibernate和Spring的组合)作为基础框架,并引入...

    compass完整可用项目

    此项目对于理解Compass和Lucene在实际应用中的使用,以及如何结合SSH框架开发Java Web应用具有很高的学习价值。通过分析和研究这个项目,开发者可以深入掌握Java全文搜索引擎的实现,以及如何在SSH框架下组织和管理...

    mongodb安装包和compass

    在Node.js学习过程中,MongoDB和Compass的结合使用可以帮助你更好地理解和操作数据库。通过Node.js的MongoDB驱动,你可以编写JavaScript代码来与MongoDB交互,创建和查询集合,执行CRUD(创建、读取、更新、删除)...

    Lucene+compass+spring+jdbc+庖丁的一个例子

    接着,他们可能会展示如何通过Spring的依赖注入来调用搜索服务,并使用Lucene和Compass提供的API来执行查询。最后,这个例子可能会涵盖如何优化搜索性能,以及如何处理索引和查询时可能出现的问题。 由于没有具体的...

Global site tag (gtag.js) - Google Analytics