zoukankan      html  css  js  c++  java
  • Compass入门 及于spring和ibatis结合

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

    文章分类:Java编程

    • 开始之前
    • 什么是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>  

    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. }  
    @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>  
     

    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内容 + 代码。演讲和写文章确实很不同,感觉很多地方还说不清楚,因为内容太多了吧,看来自己的书面组织能力还有待提高啊~

  • 相关阅读:
    oracle如何实现自增?----用序列sequence的方法来实现
    win7旗舰版安装 oracle 10g 不能进入图形界面的问题
    MBA都需要学习哪些课程
    查看Oracle当前用户下的(表视图,同义词...)
    辽宁省全国计算机等级考试 网上报名须知
    大学毕业之后的几年 你能考哪些证书
    plsql启动报 Using filter for all users can lead to poor perform
    hive web界面管理
    hive常用命令
    hive-site.xml
  • 原文地址:https://www.cnblogs.com/liaomin416100569/p/9331826.html
Copyright © 2011-2022 走看看