全文检索 Compass 配置使用

我们在使用Lucene管理Document(对应数据库中表的行或记录)时,难免有些复杂,并且在做增量索引时会比较繁琐,因此需要用到Compass。 Compass对Lucene的使用就如同Hibernate和对Jdbc的使用,Compass的工作流程如下:

全文检索 Compass 配置使用_第1张图片

本文使用Compass2.2版本,所需jar如下:

全文检索 Compass 配置使用_第2张图片

使用compass的步骤和使用hibernate的步骤基本一致:

使用hibernate时步骤一般为:

1.建立实体类,也就是Entity,如Student,Teacher,这些实体类。

2.配置实体类到数据库的映射。配置方法一般有两种:

  (1)使用xml。如(Student.hbm.xml)

  (2)使用annotation 注解 @Entity ,@Id等

    Hiberante中要求每个实体都要有个标识(Id),compass中也这么要求。

3.使用hibernate的API操作实体

Configuration cfg = new Configuration().configure(); //默认加载hibernate.cfg.xml

SessionFactory sessionFactory =cfg.buildSessionFactory(); //全局唯一

Session session = sessionFactory.openSession();

session.beginTransaction(); //开启事务

session.save(xxx);//保存

session.delete(xxx);//删除

session.get(xxx.class,id)//获得对象

........//其他操作

session.getTransaction().commit(); //提交事务

session.close(); //关闭session

 

而使用compass 和 hibernate的步骤几乎是一样的:

1.建立实体类,如Student,Teacher等实体类。

2.配置实体类到索引库的映射。

以Student类为例:

@Entity //在hibernate中,使用@Entity将Student类映射到数据库的student表
@Searchable(alias="product") //在compass中,使用@Searchable将Student映射到索引库中的 product 文档(Document),alias用来指定该实体类对应的document的名称,不设置alias则默认使用小写的类名。如果searchable的root属性设为false,则该类不会被创建为一个单独的document。一般该类作为另外一个类的组件时,才设置该属性为false。这事要想通过该类的属性搜索该类就会报错。
public class Student{
	//hibernate 和 compass中都规定,实体必须有一个标识字段
	private int id;
	private String name;
	private String fond;
	private Teacher teacher;
	@Id //hiberante中,使用@Id来将一个字段映射为实体的标识ID
	@SearchableId //compass中,则使用@SearchableId将一个字段映射为实体的标识ID
	public int getId(){
		return id;
	}
	/*
	 * 在hibernate中,对应属性如果不设置的话,则默认的映射为对应名称的字段;
	在compass中实体类的属性则需要使用@SearchableProperty来设置,设置用来检索的属性,以及属性值是否被索引、是否被存储,以及相关度boost
	@SearchableProperty中的name属性用来指定filed的名称;
	index指定是否建立索引,
		Index.ANALYZE表示建立索引并进行分词(为默认值),即建立索引时会对该filed进行分词,并在检索的时候可以通过该filed进行搜索;
		Index.NOT_ANALYZED 表示会对该字段建立索引,但不会进行分词;
		Index.NO 表示不会对该字段建立索引,当然也不会进行分词了;
	store表示该字段是否要被存储到索引库中,默认值为store=Store.YES;
	指定Index.NOT_ANALYZED并且指定Store.YES,则是为了搜索到实体时,将该filed值加载出来;
	boost表示相关度,相关度是一个float型的值,值越大,通过字段匹配的结果排序越靠前;
	*/
	@SearchableProperty(name="name",index=Index.ANALYZED,store=Store.YES,boost=3f)
	public String getName(){
		return name;
	}
	public String getFond(){
		return fond;
	}	
	/*
 	@SearchableComponent复合类型,该类型的对象Teacher被看做是当前类Student的一部分,一个组件,创建document时,复合类型的属性会和student的属性放在同一个document中。
	当进行查询时,会先查询主类的数据元字段,也会查询组件类如Teacher类中的字段,因为在创建document时,teacher的数据元字段作为student的一部分放到了document中。
	*/
	@SearchableComponent
	public Teacher getTeacher(){
		return teacher;
	}
	public void setTeacher(Teacher teacher){
		this.teacher = teacher;
	}
}

//把root属性设为false,表示该类不是一个独立的实体,它只是其他类(Student)的一部分
@Searchable(root=false)
public class Teacher {
	//此时该类的id就不能做为索引库中的标识了,因为该类被当做是Student的的一部分,而Student中已经有标识了。
	@SearchableProperty(name="tid",index=Index.NO,store=Store.YES)
	private int id;
	/*应为在创建索引时,该name对应的索引字段为name,而在Student中name对应的索引字段也为name,会造成冲突,
	 * 所以需要将复合类型中与主类属性名字相同的该为其他的的名称,以免冲突。
	*/
	@SearchableProperty(name="tname",index=Index.ANALYZED,store=Store.YES)
	private String name;
	@SearchableProperty(name="tage",index=Index.NO,store=Store.YES)
	private int age;
	@SearchableProperty(name="tfond",index=Index.ANALYZED,store=Store.YES)
	private String fond;
	//也就是说,查询到Teacher类的某个实体时,可以根据该实体加载出来其对应的student对象。
	@SearchableReference
	private Student student;
	//…………………………省略get/set方法	
}

3.使用Compass中的API对实体进行操作:

    Compasscompass = new CompassConfiguration().configure().bulidCompass();

    /*compass 相当于 hibernatesessionfactory

上面的configure()方法会自动去classpathcompass.cfg.xml配置文件这个方法和hibernate中的configure()方法很相似,hibernate中的该方法用来加载hibernate.cfg.xml.

     如果要制定其他名称的配置文件可以使用configure(xxx).

CompassSession相当于hibernate中的Session

*/

CompassSession compassSession = compass.openSession();

compassSession.beginTransaction(); //CompassTransaction相当于 Hiberante中的Transaction,compss中也是有事务支持的和数据库很相似也有事务回滚tx.rollback()

compassSession.create(entity)/.create(entity);//保存到索引文件

compassSession.delete(entity);//将实体从索引库中删除

compassSession.commit();

compassSession.close();

下面是测试时使用compass进行保存,查询等操作的关键代码:

@Searchable //告诉compass,将该类映射到Lucene的Document  
public class Product {  
         private Integer id;  
         private String name;  
         private String content;  
         private Float price;  
         private String note;  
         private Integer position;  
         private Integer typeid;  
           
         public Product(){}  
           
         public Product(Integer id) {  
                   this.id = id;  
         }  
   
         public Product(Integer id, String name, String content, Float price,String note,Integer typeid,Integer position) {  
                   this.id = id;  
                   this.name = name;  
                   this.content = content;  
                   this.price = price;  
                   this.note = note;  
                   this.typeid = typeid;  
                   this.position = position;  
         }  
           
         @SearchableId //compass要求每个搜索实体类都要具有一个标识属性,这点和Hibernate相似  
         public Integer getId() {  
                   return id;  
         }  
         public void setId(Integer id) {  
                   this.id = id;  
         }  
         @SearchableProperty(index=Index.NOT_ANALYZED, store=Store.YES)//store的默认值为Store.YES  
         public Integer getTypeid() {  
                   return typeid;  
         }  
   
         public void setTypeid(Integer typeid) {  
                   this.typeid = typeid;  
         }  
   
         @SearchableProperty(boost=2)//boost的默认值为1,用于设置属性在索引中的重要性  
         public String getName() {  
                   return name;  
         }  
         public void setName(String name) {  
                   this.name = name;  
         }  
   
         @SearchableProperty  
         public String getContent() {  
                   return content;  
         }  
         public void setContent(String content) {  
                   this.content = content;  
         }  
         //价格不需要进行搜索,但需要存储,如果没有存储,就需要从数据库中获取价格了  
         @SearchableProperty(index=Index.NO)//store的默认值为Store.YES  
         public Float getPrice() {  
                   return price;  
         }  
         public void setPrice(Float price) {  
                   this.price = price;  
         }  
         @SearchableProperty(store=Store.YES)  
         public String getNote() {  
                   return note;  
         }  
   
         public void setNote(String note) {  
                   this.note = note;  
         }  
         @SearchableProperty(index=Index.NOT_ANALYZED, store=Store.YES)//store的默认值为Store.YES  
         public Integer getPosition() {  
                   return position;  
         }  
         public void setPosition(Integer position) {  
                   this.position = position;  
         }        
}  


 

public class ProductSearchBean {  
         private Compass compass = null;//-->SessionFactory  
           
         public ProductSearchBean(){  
                    try {  
                             //编程式配置  
                            compass = new CompassAnnotationsConfiguration()  
                            .setSetting(CompassEnvironment.CONNECTION, "file://indexfile")  
                            //.setSetting(CompassEnvironment.CONNECTION, "ram://index")//在内存中建立索引  
                            .setSetting("compass.engine.analyzer.default.type", "net.paoding.analysis.analyzer.PaodingAnalyzer")
                            .setSetting("compass.engine.highlighter.default.formatter.simple.pre","")  
                            .setSetting("compass.engine.highlighter.default.formatter.simple.post","")  
                            
                            .addScan("lxq.compass").buildCompass();  
                   } catch (Exception e) {  
                            e.printStackTrace();  
                   }  
         }  
          
         public void buildIndex(){  
                   CompassSession session = null;  
                   CompassTransaction tx = null;  
                   try {  
                            session = compass.openSession();  
                            tx = session.beginTransaction();        
                            Product p1 = new Product(12,"c瑜珈球","非常好的瑜珈球",12f, "www", 2, 12);  
                            session.create(p1);  
                            Product p2 = new Product(35,"b瑜珈球","天花板瑜珈球,good",42f, "mmm",2,9);  
                            session.create(p2);  
                            Product p3 = new Product(8,"a蓝球瑜珈球","蓝球小子",125f, "ppp",5,8);                             
                            session.create(p3);  
                            tx.commit();  
                   } catch (CompassException e) {  
                            e.printStackTrace();  
                            tx.rollback();  
                   }finally{  
                            if(session!=null && !session.isClosed()) session.close();  
                   }  
         }  
   
         public void deleteIndex(Product product) {  
                   CompassSession session = null;  
                   CompassTransaction tx = null;  
                   try {  
                            session = compass.openSession();  
                            tx = session.beginTransaction();  
                       session.delete(product);  
                       tx.commit();  
                   } catch (CompassException e) {  
                            e.printStackTrace();  
                            tx.rollback();  
                   }finally{  
                            if(session!=null && !session.isClosed()) session.close();  
                   }  
         }  
   
         public void updateIndex(Product product) {  
                   CompassSession session = null;  
                   CompassTransaction tx = null;  
                   try {  
                      session = compass.openSession();  
                      tx = session.beginTransaction();  
                      session.delete(product);  
                      session.save(product);  
                      tx.commit();  
                   } catch (CompassException e) {  
                            e.printStackTrace();  
                            tx.rollback();  
                   }finally{  
                            if(session!=null && !session.isClosed()) session.close();  
                   }  
         }  
   
         public void destroy(){  
                   compass.close();  
         }  
           
         public QueryResult search(String keyword, int firstIndex, int maxResult) {  
                   QueryResult qr = new QueryResult();  
                   CompassSession session = null;  
                   CompassTransaction tx = null;  
                   try {  
                             session = compass.openSession();  
                             tx = session.beginTransaction();  
                            //对所有索引Field进行搜索,你也可以指定对某个Field搜索,如:"name:jack",如果想指定多个字段可以用空格和"+"隔开如"name:jack +content:xxx"  
                             CompassHits hits = session.find(keyword); 
                             List products = new ArrayList();  
                             int length = firstIndex+ maxResult;  
                             if(length>hits.length()) length = hits.length();                            
                             for(int i=firstIndex; i search(String keyword, Integer typeid, int firstIndex, int maxResult) {  
                   QueryResult qr = new QueryResult();  
                   CompassSession session = null;  
                   CompassTransaction tx = null;  
                   try {  
                             session = compass.openSession();  
                             tx = session.beginTransaction();  
                             //查询指定类别的匹配记录,并按position降序排序  
                             CompassQueryBuilder queryBuilder = session.queryBuilder();  
                             CompassHits hits = queryBuilder.bool()  
                                    .addMust(queryBuilder.spanEq("typeid", typeid))  
                                    .addMust(queryBuilder.queryString(keyword).toQuery())  
                                  .toQuery().addSort("position", SortPropertyType.FLOAT, SortDirection.REVERSE)  
                                  .hits();//sql: typeid=1 and (xxxx like ?) order by positoin desc  
                               
                             List products = new ArrayList();  
                             int length = firstIndex+ maxResult;  
                             if(length>hits.length()) length = hits.length();                            
                             for(int i=firstIndex; i

 

补充说明:

一、 这两段代码具有一样的功能,下面的代码另外还多了个很重要的功能,自动选择正文中最匹配关键字的内容中的一部分输出。因为很多时候一篇文章几千字,我们只想显示有关键字的那部分的摘要,这时候这个功能就很方便。

Stringcontent = hits.highlighter(i) .fragment("content"); 

String content =hits.highlighter(i).setTextTokenizer(CompassHighlighter.TextTokenizer.AUTO).fragment("content"); 

 

二、另外在getContent()方法上的@SearchableProperty中还可以加入例如converter ="htmlPropertyConverter",主要是用来将文章中的HTML标签进行过滤获取纯文本,在建立到索引中。在配置文件中添加

  
  
              
                  
                      
                  
              
  
 

然后就可以自己写实现类了,我也是网上看到的,给个链接http://blog.csdn.net/u010469430/article/details/12384347。

 

三、多种查询方式

// 查询方式一:使用查询字符串(可以有查询语法)
 // CompassHits hits = session.find(queryString);
 // -----------------------------------------------------------------
 // 查询方式二:构建CompassQuery对象
 // 1,查询所有
 CompassQuery query1 = session.queryBuilder().matchAll();
 
 // 2,关键词查询
 CompassQuery query2 = session.queryBuilder().term("title", "lucene");
 
 // 3,范围查询
 CompassQuery query3 = session.queryBuilder().between("id", 5, 15, true);
 
 // 4,通配符查询
 CompassQuery query4 = session.queryBuilder().wildcard("title", "lu*n?");
 
 // 5,短语查询
 // 设定精确间隔的匹配方式,写法1
 CompassMultiPhraseQueryBuilder qb = session.queryBuilder().multiPhrase("title");
 qb.add("lucene", 0); // 第一个词位置从0开始
 qb.add("工作", 2); // 第二个词位置从2开始
 CompassQuery query5 = qb.toQuery();
 // 设定精确间隔的匹配方式,写法2
 CompassQuery query6 = session.queryBuilder().multiPhrase("title")//
 .add("lucene", 0) // 第一个词位置从0开始
 .add("工作", 2) // 第二个词位置从2开始
 .toQuery();
 // 设定最多间隔的匹配方式
 CompassQuery query7 = session.queryBuilder().multiPhrase("title")//
 .add("lucene") //
 .add("工作") //
 .setSlop(5) // 指定的词之间的最长间隔不超过5个词
 .toQuery();
 // 6,布尔查询
 CompassQuery query = session.queryBuilder().bool()//
 // .addMust(query)
 // .addMustNot(query)
 // .addShould(query)
 .addMust(query1)//
 .addMustNot(query3)//
 .toQuery();
 CompassHits hits = query.hits();


 

四、当然上面可以不用编程式配置,而通过Compass compass= new CompassConfiguration().configure().bulidCompass();使用类似如下的配置文件。




	

		
		
			
		
		
		
			
		
		
		
			
		
		
		
			
				
			
			
			
							       
		
		
	



 

CompassSpring的集成

 

先思考一下compass不与spring集成时的情况。

我们将一个entity保存到数据库的同时,也要将该实体相关的数据信息保存到索引库中。所以代码常为一下情况:

Public  void saveStudent(Student stu){

        hibernateTeplate.save(stu);//保存到数据库中

      compassSession.save(stu);//保存到索引库中

}

我们有一点需要保证的是,必须在数据库保存成功后才能将实体对象保存到索引库中,然而在没有任何外界条件限制的情况先,数据库的事务和compass的事务是两个不同体系的事务,他们不可能自动的将事务并为一起。这样就无法保证整个操作的流程控制在同一个事务中,所以我们就要想办法来解决这个问题。

使用compassspring集成,能很好的解决这个问题,spring会为hibernatecompass提供同一个事务管理,将整个操作流程(如上的saveStudent()方法)纳入同一个事务支持当中。

下面看一下配置中JPA(hibernate)compassspring的集成:

其中JPA(hibernate)spring集成与前面完全一致,就是在后面加了一个compass的配置:



	


 		
  
 

        

   



  
          
          	

	
		
			cn.itcast.bean.product.ProductInfo
			cn.itcast.bean.product.Brand
			cn.itcast.bean.product.ProductStyle
			cn.itcast.bean.product.ProductType
		
	
	



				net.paoding.analysis.analyzer.PaodingAnalyzer




			
file://e:/index

  
 200  
  

			]]>

			]]>


			
org.compass.spring.transaction.SpringSyncTransactionFactory

		
	

	

 

按照上面的配置你仍然需要在代码中写相应的创建、删除索引的语句,在配置文件中添加下面的代码就可以一切都自动化了。 

CompassGps - Gps的核心模块,管理GpsDevice,有两种实现:SingleCompassGpsDualCompassGps

CompassGpsDevice - 处理各种数据源到索引的操作:JDBC, Hibernate,iBatis等。不能独立使用而必须融合到CompassGps中。




	
	
		

				

				
					
					

			

				
				
				
		 	
		



 

 

 

本文参考文章如下:

http://blog.csdn.net/u010469430/article/details/12384139

http://blog.csdn.net/u010469430/article/details/12384347

http://blog.csdn.net/xpsharp/article/details/8362398



你可能感兴趣的:(Compass)