compass 使用详解

Java代码   收藏代码
  1. 我们在使用lucene管理document时,难免有些复杂,并且在做增量索引的时候会比较繁琐,现介绍compass如下:  
  2. compass对lucene的使用就如同Hibernate和对jdbc的使用。  
  3. Compass的使用步骤:  
  4. Hibernate的实现步骤是:  
  5. 1》  设计实体  
  6. 2》  配置映射元数据 (xml / 注解—Hibernate3才推出来的)  
  7. 3》  利用Hibernate的api完成对实体的CURD  
  8. 我们目前使用compass的操作步骤就与Hibernate的基本一样的:  
  9. Hibernate的第二步是映射到数据库,而compass是映射到收索引擎里面去。  
  10. 1》  设计收索实体 – 就 是一个普通的javabean  
  11. 你要写这么一个实体,定义一些属性,好比产品的id、名称  
  12. 2》  配置映射元数据 – 针对收索引擎映射-我们采用主注解的方式  
  13. 我们使用@Searchable 标注映射为收索实体,映射到Lucene中的document  
  14. 假设是采用注解的形式,我们就需要在实体和属性上面加上一些注解  
  15. @Entity (映射到数据库中的表)   
  16. @Searchable  –> 这个注解把该类声明为搜索实体,映射到lucene中的document  
  17. Public class Product{  
  18.            @Id (Hibernate用来表示实体的标识属性)  
  19.            @SearchableId (compass标注为标识属性)  
  20.            Private Integer id;  
  21.            @Column()  
  22.            @SearchableProperty  à  映射搜索属性  
  23.            Private String name;  
  24. }  
  25.    
  26. 3>利用compass api完成对实体的添/删/查操作  
  27.   hibernate.cfg.xml / compass.cfg.xml 放在类路径下  
  28. hibernate: SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();  
  29. Compass:   Compass compass = new CompassConfiguration().configure().buildCompass();  
  30.   SessionFactory == Compass   
  31.    
  32. hibernate: Session session = sessionFactory.openSession();  
  33. compass:   CompassSession session = compass.openSession();  
  34.            Session = CompassSession  
  35.    
  36. Hibernate:  session.beginTransaction();  
  37. compass:    session.beginTransaction();  
  38.    
  39. Hibernate:  session.save(product)/persist();  
  40. compass:    session.save(product)/create();  
  41.    
  42. Hibernate:  session.getTransaction().commit();  
  43. compass:    session.getTransaction().commit();  
  44.    
  45.   session.close();  
  46.   sessionFactory.close();  
  47.    
  48.          学习一下compass映射注解:常用的就5个  
  49.          @Searchable //告诉compass,将该类映射到lucene的Document  
  50.          注意注解如果标注在属性上只能标注在get方法上面  
  51.          @SearchableId //compass要求每个搜索实体类都要具有一个标识属性,这点和Hibernate相似  
  52.          @SearchableProperty(index=Index.NOT_ANALYZED ,store=Store.YES)// store的默认值为Store.YES  
  53. 类别id不需要分词,蛋需要索引并存储  
  54. Index。UN_TOKENIZED 不对该field进行分词,但是要索引,该属性已过时,建议产用NOT__ANALYZED替换  
  55. Index.TOKENIZED:先分词后索引。该属性已过时,建议采用ANALYZED替换  
  56. Inde.NOT_ANALYZED 不分词,但建立索引  
  57. Index.ANALYZED 分词并且建立索引  
  58.    
  59. @SearchableId Property(boost=2)//boost的默认值为1,用户设置属性在索引中的重要性  
  60. 如下:  
  61. @Searchable //告诉compass,将该类映射到Lucene的Document  
  62. public class Product {  
  63.          private Integer id;  
  64.          private String name;  
  65.          private String content;  
  66.          private Float price;  
  67.          private String note;  
  68.          private Integer position;  
  69.          private Integer typeid;  
  70.            
  71.          public Product(){}  
  72.            
  73.          public Product(Integer id) {  
  74.                    this.id = id;  
  75.          }  
  76.    
  77.          public Product(Integer id, String name, String content, Float price,String note,Integer typeid,Integer position) {  
  78.                    this.id = id;  
  79.                    this.name = name;  
  80.                    this.content = content;  
  81.                    this.price = price;  
  82.                    this.note = note;  
  83.                    this.typeid = typeid;  
  84.                    this.position = position;  
  85.          }  
  86.            
  87.          @SearchableId //compass要求每个搜索实体类都要具有一个标识属性,这点和Hibernate相似  
  88.          public Integer getId() {  
  89.                    return id;  
  90.          }  
  91.          public void setId(Integer id) {  
  92.                    this.id = id;  
  93.          }  
  94.          //类别id不需要分词,但需要索引并储存  
  95.          //Index.UN_TOKENIZED:不对该Field进行分词,但是要索引.该属性已过时,建议采用NOT_ANALYZED替换  
  96.     //Index.TOKENIZED:先分词后索引。该属性已过时,建议采用ANALYZED替换  
  97.          //Index.NOT_ANALYZED:不分词,但建立索引  
  98.          //Index.ANALYZED :分词并且建立索引  
  99.            
  100.          @SearchableComponent //关联的符合索引,专门用来标注复合类型  
  101.          那么被标注的这个属性对应的类,我们也要标注一下为收索实体,但是这个搜索实体他不是单独存在的,他只是最为产品搜索实体的一部分  
  102. @Searchable(root=false)  
  103. @SearchableProperty(index=Index.NO ,store=Store.YES)  
  104.          我们对他的主键不需要索引只需要存储  
  105.          当你存在双向关系的时候,并且需要引用会对应的实体,反指引用  
  106.          @SearchableReference  
  107.    
  108. @SearchableProperty(index=Index.NOT_ANALYZED, store=Store.YES)//store的默认值为Store.YES  
  109.          public Integer getTypeid() {  
  110.                    return typeid;  
  111.          }  
  112.    
  113.          public void setTypeid(Integer typeid) {  
  114.                    this.typeid = typeid;  
  115.          }  
  116.    
  117.          @SearchableProperty(boost=2)//boost的默认值为1,用于设置属性在索引中的重要性  
  118.          public String getName() {  
  119.                    return name;  
  120.          }  
  121.          public void setName(String name) {  
  122.                    this.name = name;  
  123.          }  
  124.    
  125.          @SearchableProperty  
  126.          public String getContent() {  
  127.                    return content;  
  128.          }  
  129.          public void setContent(String content) {  
  130.                    this.content = content;  
  131.          }  
  132.          //价格不需要进行搜索,但需要存储,如果没有存储,就需要从数据库中获取价格了  
  133.          @SearchableProperty(index=Index.NO)//store的默认值为Store.YES  
  134.          public Float getPrice() {  
  135.                    return price;  
  136.          }  
  137.          public void setPrice(Float price) {  
  138.                    this.price = price;  
  139.          }  
  140.          @SearchableProperty(store=Store.YES)  
  141.          public String getNote() {  
  142.                    return note;  
  143.          }  
  144.    
  145.          public void setNote(String note) {  
  146.                    this.note = note;  
  147.          }  
  148.          @SearchableProperty(index=Index.NOT_ANALYZED, store=Store.YES)//store的默认值为Store.YES  
  149.          public Integer getPosition() {  
  150.                    return position;  
  151.          }  
  152.    
  153.          public void setPosition(Integer position) {  
  154.                    this.position = position;  
  155.          }  
  156.            
  157.            
  158. }  
  159.    
  160.    
  161. 我们不集成spring的编程配置和使用方式如下:  
  162. import java.util.ArrayList;  
  163. import java.util.List;  
  164.    
  165. import org.compass.annotations.config.CompassAnnotationsConfiguration;  
  166. import org.compass.core.Compass;  
  167. import org.compass.core.CompassException;  
  168. import org.compass.core.CompassHits;  
  169. import org.compass.core.CompassQueryBuilder;  
  170. import org.compass.core.CompassSession;  
  171. import org.compass.core.CompassTransaction;  
  172. import org.compass.core.CompassQuery.SortDirection;  
  173. import org.compass.core.CompassQuery.SortPropertyType;  
  174. import org.compass.core.config.CompassEnvironment;  
  175.    
  176. import cn.itcast.bean.Product;  
  177. import cn.itcast.bean.QueryResult;  
  178. import cn.itcast.compass.service.ProductSearch;  
  179.    
  180. public class ProductSearchBean implements ProductSearch {  
  181.          private Compass compass = null;//-->SessionFactory  
  182.            
  183.          public ProductSearchBean(){  
  184.                     try {  
  185.                              //编程式配置  
  186.                             compass = new CompassAnnotationsConfiguration()  
  187.                             .setSetting(CompassEnvironment.CONNECTION, "[url=file://indexfile]file://indexfile[/url]")  
  188.                             //.setSetting(CompassEnvironment.CONNECTION, "ram://index")//在内存中建立索引  
  189.                             .setSetting("compass.engine.highlighter.default.formatter.simple.pre","<font color='red'>")  
  190.                             .setSetting("compass.engine.highlighter.default.formatter.simple.post","</font>")  
  191.                             .addScan("cn.itcast.bean").buildCompass();  
  192.                    } catch (Exception e) {  
  193.                             e.printStackTrace();  
  194.                    }  
  195.          }  
  196.            
  197.          //compass支持增量索引,社会上很多公司,他们的产品都没有实现增量索引,1>lucene版本比较低,不支持增量索引,2>要增量索引,技术要求稍微有点高  
  198.          //(晚上 2-3,定时器,把索引文件删除,重新生成索引)实时性不强,在索引文件更新的时候,用户是访问不了的  
  199.          public void buildIndex(){  
  200.                    CompassSession session = null;  
  201.                    CompassTransaction tx = null;  
  202.                    try {  
  203.                             session = compass.openSession();  
  204.                             tx = session.beginTransaction();        
  205.                             Product p1 = new Product(12,"c瑜珈球","非常好的瑜珈球",12f, "www"212);  
  206.                             session.create(p1);  
  207.                             Product p2 = new Product(35,"b瑜珈球","天花板瑜珈球,good",42f, "mmm",2,9);  
  208.                             session.create(p2);  
  209.                             Product p3 = new Product(8,"a蓝球瑜珈球","蓝球小子",125f, "ppp",5,8);                             
  210.                             session.create(p3);  
  211.                             tx.commit();  
  212.                    } catch (CompassException e) {  
  213.                             e.printStackTrace();  
  214.                             tx.rollback();  
  215.                    }finally{  
  216.                             if(session!=null && !session.isClosed()) session.close();  
  217.                    }  
  218.          }  
  219.    
  220.          public void deleteIndex(Product product) {  
  221.                    CompassSession session = null;  
  222.                    CompassTransaction tx = null;  
  223.                    try {  
  224.                             session = compass.openSession();  
  225.                             tx = session.beginTransaction();  
  226.                        session.delete(product);  
  227.                        tx.commit();  
  228.                    } catch (CompassException e) {  
  229.                             e.printStackTrace();  
  230.                             tx.rollback();  
  231.                    }finally{  
  232.                             if(session!=null && !session.isClosed()) session.close();  
  233.                    }  
  234.          }  
  235.    
  236.          public void updateIndex(Product product) {  
  237.                    CompassSession session = null;  
  238.                    CompassTransaction tx = null;  
  239.                    try {  
  240.                       session = compass.openSession();  
  241.                       tx = session.beginTransaction();  
  242.                       session.delete(product);  
  243.                       session.save(product);  
  244.                       tx.commit();  
  245.                    } catch (CompassException e) {  
  246.                             e.printStackTrace();  
  247.                             tx.rollback();  
  248.                    }finally{  
  249.                             if(session!=null && !session.isClosed()) session.close();  
  250.                    }  
  251.          }  
  252.    
  253.          public void destroy(){  
  254.                    compass.close();  
  255.          }  
  256.            
  257.          public QueryResult<Product> search(String keyword, int firstIndex, int maxResult) {  
  258.                    QueryResult<Product> qr = new QueryResult<Product>();  
  259.                    CompassSession session = null;  
  260.                    CompassTransaction tx = null;  
  261.                    try {  
  262.                              session = compass.openSession();  
  263.                              tx = session.beginTransaction();  
  264.                             //对所有索引Field进行搜索,你也可以指定对某个Field搜索,如:"name:jack",如果想指定多个字段可以用空格和"+"隔开如"name:jack +content:xxx"  
  265.                              CompassHits hits = session.find(keyword);             
  266.                              List<Product> products = new ArrayList<Product>();  
  267.                              int length = firstIndex+ maxResult;  
  268.                              if(length>hits.length()) length = hits.length();                            
  269.                              for(int i=firstIndex; i<length; i++){  
  270.                                       Product product = (Product)hits.data(i);  
  271.                                       product.setContent(hits.highlighter(i).fragment("content"));  
  272.                                       products.add(product);  
  273.                              }  
  274.                              qr.setResultlist(products);  
  275.                              qr.setTotalrecord(hits.length());  
  276.                              hits.close();  
  277.                    } catch (CompassException e) {  
  278.                             e.printStackTrace();  
  279.                             tx.rollback();  
  280.                    }finally{  
  281.                             if(session!=null && !session.isClosed()) session.close();  
  282.                    }  
  283.                    return qr;  
  284.          }  
  285.            
  286.          public QueryResult<Product> search(String keyword, Integer typeid, int firstIndex, int maxResult) {  
  287.                    QueryResult<Product> qr = new QueryResult<Product>();  
  288.                    CompassSession session = null;  
  289.                    CompassTransaction tx = null;  
  290.                    try {  
  291.                              session = compass.openSession();  
  292.                              tx = session.beginTransaction();  
  293.                              //查询指定类别的匹配记录,并按position降序排序  
  294.                              CompassQueryBuilder queryBuilder = session.queryBuilder();  
  295.                              CompassHits hits = queryBuilder.bool()  
  296.                                     .addMust(queryBuilder.spanEq("typeid", typeid))  
  297.                                     .addMust(queryBuilder.queryString(keyword).toQuery())  
  298.                                   .toQuery().addSort("position", SortPropertyType.FLOAT, SortDirection.REVERSE)  
  299.                                   .hits();//sql: typeid=1 and (xxxx like ?) order by positoin desc  
  300.                                
  301.                              List<Product> products = new ArrayList<Product>();  
  302.                              int length = firstIndex+ maxResult;  
  303.                              if(length>hits.length()) length = hits.length();                            
  304.                              for(int i=firstIndex; i<length; i++){  
  305.                                       Product product = (Product)hits.data(i);  
  306.                                       product.setContent(hits.highlighter(i).fragment("content"));  
  307.                                       products.add(product);  
  308.                              }  
  309.                              qr.setResultlist(products);  
  310.                              qr.setTotalrecord(hits.length());  
  311.                              hits.close();  
  312.                    } catch (CompassException e) {  
  313.                             e.printStackTrace();  
  314.                             tx.rollback();  
  315.                    }finally{  
  316.                             if(session!=null && !session.isClosed()) session.close();  
  317.                    }  
  318.                    return qr;  
  319.          }  
  320. }  


         //compass支持增量索引,社会上很多公司,他们的产品都没有实现增量索引,1>lucene版本比较低,不支持增量索引,2>要增量索引,技术要求稍微有点高 
         //(晚上 2-3,定时器,把索引文件删除,重新生成索引)实时性不强,在索引文件更新的时候,用户是访问不了的 

以上基本都为讲解,下面是具体的开发步骤: 
步骤一: 
导jar:compass的两个文件,疑问logging文件一般我们已经存在了,lucene的六个文件 
步骤二: 
配置映射元数据: 
设计实体,我们实体已经存在了,所以不用设计了,直接加注解 
我们映射产品: 
首先我们要加上搜索id 
然后我们要分析一下那些是需要搜索的,哪些是不需要搜索的,但是需要显示在搜索结果中的。如果不需要显示也不需要索引就不管他 
         第三步: 
         我们对索引进行填、删、查 
         我们对产品进行保存的时候,我们就应该把索引也保持进去。 
         方式一:我们可以重写我们servicebean的保持方法。添加一个保存到索引里面去的方法。这样我们就存在一个问题,两个保存,有一个保存失败了,另一个保存就无法执行。就导致了数据不同,无法保证两种保存在同一个事物中 
         方式二:把compass集成到spring中,让他使用spring的事物管理功能。 
在我们的spring中添加代码如下: 

Java代码   收藏代码
  1. <bean id="compass" class="org.compass.spring.LocalCompassBean">  
  2.      <property name="classMappings">  
  3.          <list>  
  4.             <value>cn.itcast.bean.product.ProductInfo</value>  
  5.             <value>cn.itcast.bean.product.Brand</value>  
  6.             <value>cn.itcast.bean.product.ProductStyle</value>  
  7.             <value>cn.itcast.bean.product.ProductType</value>  
  8.          </list>  
  9.      </property>  
  10.      <property name="compassSettings">  
  11.          <props>  
  12.             <prop key="compass.engine.analyzer.default.type">net.paoding.analysis.analyzer.PaodingAnalyzer</prop>  
  13.             <prop key="compass.engine.connection">file://d:/index</prop>  
  14.             <!-- 在内存中建立索引  
  15.             <prop key="compass.engine.connection">ram://index</prop>  
  16.             -->  
  17.             <prop key="compass.engine.highlighter.default.formatter.simple.pre"><![CDATA[<font color='red'>]]></prop>  
  18.             <prop key="compass.engine.highlighter.default.formatter.simple.post"><![CDATA[</font>]]></prop>  
  19.             <prop key="compass.transaction.factory">org.compass.spring.transaction.SpringSyncTransactionFactory</prop>  
  20.          </props>  
  21.      </property>  
  22.      <property name="transactionManager" ref="transactionManager" />  
  23.   </bean>  

你可能感兴趣的:(spring,Hibernate,session,null,Lucene,产品)