Compass学习文档 (转) ,来自http://www.blogjava.net/liuwentao253/archive/2007/02/06/98210.html

来源:互联网 发布:php 开源电商 编辑:程序博客网 时间:2024/05/21 22:21

Compass是第一个实现java搜索引擎的开源框架,它是基于Lucene之上的,提供

更简单的搜索引擎API,
事务支持,
对象到搜索引擎映射(Annotations 
&  XML),
Xml到搜索引擎映射,
可以和Hibernate,Spring集成

,功能非常的强大。如果用Hibernate,Spring做的项目需要搜索引擎的话,Compass是个非常好的选择。个人认为:如果说Lucene是搜索引擎中的JDBC,那么Compass就是Hibernate。而Compass和Hibernate不仅仅是比喻的像,它们的类和用法,和作用也非常的像。Compass是用面向对象编程方法来实现搜索。如果会Hibernate的话学Compass是非常容易的。
大家可以到http://www.opensymphony.com/compass/download.action去下载最新的版本。2006年8月28日Compass 1.1 M1 发布,用的是Lucene2.0,现在讲的就是这个版本。
虽然有人说Hibernate3.1以后版本自带了对Lucene的支持,Compass好像没用,但是只要看一下Hibernate源代码可以看出Hibernate对Lucene的支持很简陋,且不支持事务并且Hibernate3.2用的还是Lucene版本是Lucene1.4.3,所以说当做大的项目的时候Compass还是非常有必要的。

还是先看个HelloWorld程序:(这里的测试功能的例子都是用的JUnit测试用例,为方便阅读异常全部抛出)

一共4个文件Article.java, compass.cfg.xml,Article.cpm.xml,JUnit插入测试。

1.Article.java:

package  org.li.compass;

import  java.util.Date;

public   class  Article  {
    
private   long  id;
    
private  String title;
    
private  String content;
    
private  Date publishDate;

    
public  String getContent()      {
        
return  content;
    }


    
public   void  setContent(String content)      {
        
this .content  =  content;
    }


    
public  Date getPublishDate()      {
        
return  publishDate;
    }


    
public   void  setPublishDate(Date publishDate)      {
        
this .publishDate  =  publishDate;
    }


    
public  String getTitle()      {
        
return  title;
    }


    
public   void  setTitle(String title)      {
        
this .title  =  title;
    }


    
public   long  getId()      {
        
return  id;
    }


    
public   void  setId( long  id)      {
        
this .id  =  id;
    }

}

上面就是一个Article的POJO类 , 上面有文章题目,内容,发布时间,这里的id是compass必须的(有点和数据库一样了)。

2.compass.cfg.xml

<! DOCTYPE compass - core - configuration PUBLIC
    
" -//Compass/Compass Core Configuration DTD 1.0//EN "
    
" http://www.opensymphony.com/compass/dtd/compass-core-configuration.dtd " >

< compass - core - configuration >
    
< compass >
    
<!--  这里配置的是索引的相对路径  -->
    
< setting name = " compass.engine.connection " > target / test </ setting >
    
<!--  这里是每个对象的映射文件  -->
        
< mapping resource = " org/li/compass/Article.cpm.xml " />
    
</ compass >
</ compass - core - configuration >

这是Compass的配置文件上面标明了索引目录和映射文件。映射好文件了就看看这个映射的什么吧
3. Article.cpm.xml

<! DOCTYPE compass - core - mapping PUBLIC 
    
" -//Compass/Compass Core Mapping DTD 1.0//EN "
    
" http://www.opensymphony.com/compass/dtd/compass-core-mapping.dtd " >

< compass - core - mapping  package = " org.li.compass " >
    
< class  name = " Article "  alias = " article " >
        
<!--  这是必须有的  -->
        
< id name = " id " />
        
<!--  你可以通过这个配置来在底层给这个对象加一个Field( " type " , " java " -->
        
< constant >
            
< meta - data > type </ meta - data >
            
< meta - data - value > java </ meta - data - value >
        
</ constant >
        
<!--  配置一下属性  -->
        
< property name = " title " >
            
< meta - data > titleIndex </ meta - data >
        
</ property >
        
< property name = " content " >
            
< meta - data > contentIndex </ meta - data >
        
</ property >
        
< property name = " publishDate " >
            
< meta - data > publishDateIndex </ meta - data >
        
</ property >
    
</ class >
</ compass - core - mapping >

这个配置应该可以看的懂吧可能会有人问meta-data是干什么用的??
它的值是作为底层Field的名字,如果没有配置的话Compass用$article/…来代替。而它的作用是配置对象的属性的储存形式,Compass就是读取它来new Field()的:

<! ELEMENT meta - data (
    #PCDATA
)
>
    
<! ATTLIST meta - data store (no | yes | compress)  " yes " >
    
<! ATTLIST meta - data index (no | tokenized | un_tokenized)  " tokenized " >
    
<! ATTLIST meta - data term - vector (no | yes | positions | offsets | positions_offsets)  " no " >
    
<! ATTLIST meta - data reverse (no | reader | string)  " no " >
    
<! ATTLIST meta - data analyzer CDATA #IMPLIED >
    
<! ATTLIST meta - data exclude - from - all ( true | false ) #IMPLIED >
    
<! ATTLIST meta - data converter CDATA #IMPLIED >
    
<! ATTLIST meta - data format CDATA #IMPLIED >
    
<! ATTLIST meta - data boost CDATA #IMPLIED >

4.JUnit插入测试

public   void  InsertCompass()      {
    CompassConfiguration comConfig 
=   new  CompassConfiguration().configure().addClass(Article. class );
        Compass com 
=  comConfig.buildCompass();
        CompassSession comSession 
=  com.openSession();
        CompassTransaction comTx 
=  comSession.beginTransaction();
        
        Article article 
=   new  Article();
        article.setContent(
" Compass是第一个基于lucene的java开源框架 " );
        article.setTitle(
" 学习Compass " );
        article.setPublishDate(
new  Date());
        comSession.save(article);

        comTx.commit();
    }

当大家看到这里的时候就看出来Compass和Hibernate太像了。如果会Hibernate的话,学Compass将是非常容易的。
看看效果如何:

public   void  LoadCompass()      {
        CompassConfiguration comConfig 
=   new  CompassConfiguration().configure().addClass(Article. class );
        Compass com 
=  comConfig.buildCompass();
        CompassSession comSession 
=  com.openSession();
        CompassTransaction comTx 
=  comSession.beginTransaction();
        
        Article article 
=  (Article)comSession.load(Article. class 0 );
        System.out.println(article.getTitle());
        System.out.println(article.getContent());
        System.out.println(article.getPublishDate());
    }

结果:

学习Compass
Compass是第一个基于lucene的java开源框架
Sat Sep 
23   00 : 51 : 35  CST  2006

注意:和其它的框架一样,Compass也是需要一定的配置的,而Compass的数据配置可分为Annotations,DTD验证的XML和Schema验证的XML。这里用的是dtd验证的XML配置。

我们可以用Lucene做一下检测嘛
JUnit测试用例:

public   void  TestArticle()  throws  ParseException, IOException      {
        QueryParser queryParser 
=   new  QueryParser( " titleIndex " , new  StandardAnalyzer());
        Query query 
=  queryParser.parse( " compass " );
        IndexSearcher indexSearcher 
=   new  IndexSearcher( " target/test/index/article " );
        Hits hits 
=  indexSearcher.search(query);
        
for ( int  i = 0 ;i < hits.length();i ++ )          {
            Document doc 
=  hits.doc(i);
        
// 大家可以在这里设置个断点看一下doc里各个Field是什么。就会学到很多的东西
            System.out.println(doc.get( " contentIndex " ));
        }

}


上面的只讲了Compass的建立索引也就是存储对象加载对象,这里讲一下Compass的搜索查询功能。上面说了Compass和Hibernate是非常像的。Hibernate查询的时候用的是Criteriat和Query而Compass里用的是CompassQuery具有以上两个的功能。

例子

 

 

在上面的JUnit测试用例里加入: 

 

public void InsertCompass()     
        CompassConfiguration comConfig 
= new CompassConfiguration().configure().addClass(Article.class); 
        Compass com 
= comConfig.buildCompass(); 
        CompassSession comSession 
= com.openSession(); 
        CompassTransaction comTx 
= comSession.beginTransaction();   
    
        Article article 
= new Article(); 
        article.setId((
long)0); 
        article.setContent(
"Compass学习文档"); 
        article.setTitle(
"学习Compass查询"); 
        article.setPublishDate(
new Date()); 
        comSession.save(article); 

        article 
= new Article(); 
        article.setId((
long)1); 
        article.setContent(
"Compass是第一个基于lucene的java开源框架"); 
        article.setTitle(
"学习Compass"); 
        article.setPublishDate(
new Date()); 
        comSession.save(article); 

        comTx.commit(); 
}
 

就是插入两个对象数据。

 

 

下面我们就搜搜体验一下吧:

public void TestQuery()     
    CompassConfiguration comConfig 
= new CompassConfiguration().configure().addClass(Article.class); 
        Compass com 
= comConfig.buildCompass(); 
        CompassSession session 
= com.openSession(); 
        CompassTransaction tx 
= session.beginTransaction(); 

        CompassQueryBuilder builder 
= session.queryBuilder();
        CompassHits hits 
= builder.queryString("titleIndex:学习").toQuery() 
                    .addSort(
"title", CompassQuery.SortPropertyType.STRING)
                    .addSort(
"publishDate",CompassQuery.SortPropertyType.INT).hits(); 

        
for(int i=0;i<hits.getLength();i++)         
            System.out.println(((Article)hits.data(i)).getTitle()); 
        }
 
    }

 输出结果是 :

学习Compass查询 
学习Compass 

其实Compass完全没毕要那么罗嗦,它就是为了依照Hibernate来的。让会Hibernate的程序员可以很容易的掌握Compass。搜索的前一部分就不说了,和Hibernate的初始化一样且前面也讲了,从CompassHits开始吧。

 

 

可以看到:搜索就用到CompassHits,Query,CompassQueryBuilder这一点又和lucene很像。

 

 

session.queryBuilder()返回CompassQueryBuilder的对象,再调用queryString来查询搜索字串。可这个构造字串就有学问了:“titleIndex:学习”表示指明字段名搜索,如果想指明多个字段呢可以用空格和“+”隔开如:“titleIndex:学习 +contentIndex:第”

 

 

注意:查询字串里的标识不是对象的属性,而是对象的属性映射成索引的名字,这个是可以在Article.cmp.xml里看到的。还有就是一定要在两个搜索内容之间加空格要不然什么都搜不到。

 

 

 

addSort就是对搜索出的结果按一定的顺序排序。

 

 

Hits()呢就是返回hits结果集吧。

 

 

最后用个for循环利用hits.data(i)将结果遍历输出。

 

 

上面的例子达到了Hibernate中Query的功能。而CompassQuery还有和Criteriat功能一样的:再看个搜索的例子吧:

CompassConfiguration comConfig = new CompassConfiguration().configure().addClass(Article.class); 
Compass com 
= comConfig.buildCompass(); 
CompassSession session 
= com.openSession(); 
CompassTransaction comTx 
= session.beginTransaction(); 

CompassQueryBuilder queryBuilder
= session.queryBuilder(); 
CompassQuery compassQuery 
= queryBuilder.bool().addMust(queryBuilder.le("titleIndex""学习")).toQuery(); 
CompassHits hits 
= compassQuery.addSort("title", CompassQuery.SortPropertyType.STRING).hits(); 

for(int i=0;i<hits.getLength();i++
    System.out.println(((Article)hits.data(i)).getTitle()); 
}
 
comTx.commit();

CompassQuery里有lt,le,gt,ge和Criteriat是一个样的。不过Compass的jar包里没有eq这个函数,但是在Compass1.1M1的帮助文档中写着:

 

 

CompassQueryBuilder queryBuilder = session.createQueryBuilder();
queryBuilder.bool().addMust(queryBuilder.eq(
"name""jack"))
      .addMust(queryBuilder.lt(
"birthdate""19500101")).toQuery().hits();

这个可能是Compass的一个bug。

 

 

既然没有eq我们就用:

queryBuilder.bool().addMust(queryBuilder.le("titleIndex""学习")).toQuery();

做个演示吧。

 

 

结果理想的。

 

 

具体的用法和Hibernate一样,也可以查看Compass的帮助文档。