compass 使用详解

我们在使用lucene管理document时,难免有些复杂,并且在做增量索引的时候会比较繁琐,现介绍compass如下:

compass对lucene的使用就如同Hibernate和对jdbc的使用。

Compass的使用步骤:

Hibernate的实现步骤是:

1》 设计实体

2》 配置映射元数据 (xml / 注解—Hibernate3才推出来的)

3》 利用Hibernate的api完成对实体的CURD

我们目前使用compass的操作步骤就与Hibernate的基本一样的:

Hibernate的第二步是映射到数据库,而compass是映射到收索引擎里面去。

1》 设计收索实体 – 就 是一个普通的javabean

你要写这么一个实体,定义一些属性,好比产品的id、名称

2》 配置映射元数据 – 针对收索引擎映射-我们采用主注解的方式

我们使用@Searchable 标注映射为收索实体,映射到Lucene中的document

假设是采用注解的形式,我们就需要在实体和属性上面加上一些注解

@Entity (映射到数据库中的表)

@Searchable –> 这个注解把该类声明为搜索实体,映射到lucene中的document

Public class Product{

@Id (Hibernate用来表示实体的标识属性)

@SearchableId (compass标注为标识属性)

Private Integer id;

@Column()

@SearchableProperty à 映射搜索属性

Private String name;

}

3>利用compass api完成对实体的添/删/查操作

hibernate.cfg.xml / compass.cfg.xml 放在类路径下

hibernate: SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();

Compass: Compass compass = new CompassConfiguration().configure().buildCompass();

SessionFactory == Compass

hibernate: Session session = sessionFactory.openSession();

compass: CompassSession session = compass.openSession();

Session = CompassSession

Hibernate: session.beginTransaction();

compass: session.beginTransaction();

Hibernate: session.save(product)/persist();

compass: session.save(product)/create();

Hibernate: session.getTransaction().commit();

compass: session.getTransaction().commit();

session.close();

sessionFactory.close();

学习一下compass映射注解:常用的就5个

@Searchable //告诉compass,将该类映射到lucene的Document

注意注解如果标注在属性上只能标注在get方法上面

@SearchableId //compass要求每个搜索实体类都要具有一个标识属性,这点和Hibernate相似

@SearchableProperty(index=Index.NOT_ANALYZED ,store=Store.YES)// store的默认值为Store.YES

类别id不需要分词,蛋需要索引并存储

Index。UN_TOKENIZED 不对该field进行分词,但是要索引,该属性已过时,建议产用NOT__ANALYZED替换

Index.TOKENIZED:先分词后索引。该属性已过时,建议采用ANALYZED替换

Inde.NOT_ANALYZED 不分词,但建立索引

Index.ANALYZED 分词并且建立索引

@SearchableId Property(boost=2)//boost的默认值为1,用户设置属性在索引中的重要性

如下:

@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;

}

//类别id不需要分词,但需要索引并储存

//Index.UN_TOKENIZED:不对该Field进行分词,但是要索引.该属性已过时,建议采用NOT_ANALYZED替换

//Index.TOKENIZED:先分词后索引。该属性已过时,建议采用ANALYZED替换

//Index.NOT_ANALYZED:不分词,但建立索引

//Index.ANALYZED :分词并且建立索引

@SearchableComponent //关联的符合索引,专门用来标注复合类型

那么被标注的这个属性对应的类,我们也要标注一下为收索实体,但是这个搜索实体他不是单独存在的,他只是最为产品搜索实体的一部分

@Searchable(root=false)

@SearchableProperty(index=Index.NO ,store=Store.YES)

我们对他的主键不需要索引只需要存储

当你存在双向关系的时候,并且需要引用会对应的实体,反指引用

@SearchableReference

@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;

}

}

我们不集成spring的编程配置和使用方式如下:

import java.util.ArrayList;

import java.util.List;

import org.compass.annotations.config.CompassAnnotationsConfiguration;

import org.compass.core.Compass;

import org.compass.core.CompassException;

import org.compass.core.CompassHits;

import org.compass.core.CompassQueryBuilder;

import org.compass.core.CompassSession;

import org.compass.core.CompassTransaction;

import org.compass.core.CompassQuery.SortDirection;

import org.compass.core.CompassQuery.SortPropertyType;

import org.compass.core.config.CompassEnvironment;

import cn.itcast.bean.Product;

import cn.itcast.bean.QueryResult;

import cn.itcast.compass.service.ProductSearch;

public class ProductSearchBean implements ProductSearch {

private Compass compass = null;//-->SessionFactory

public ProductSearchBean(){

try {

//编程式配置

compass = new CompassAnnotationsConfiguration()

.setSetting(CompassEnvironment.CONNECTION, "file://indexfile")

//.setSetting(CompassEnvironment.CONNECTION, "ram://index")//在内存中建立索引

.setSetting("compass.engine.highlighter.default.formatter.simple.pre","<font color='red'>")

.setSetting("compass.engine.highlighter.default.formatter.simple.post","</font>")

.addScan("cn.itcast.bean").buildCompass();

} catch (Exception e) {

e.printStackTrace();

}

}

//compass支持增量索引,社会上很多公司,他们的产品都没有实现增量索引,1>lucene版本比较低,不支持增量索引,2>要增量索引,技术要求稍微有点高

//(晚上 2-3,定时器,把索引文件删除,重新生成索引)实时性不强,在索引文件更新的时候,用户是访问不了的

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<Product> search(String keyword, int firstIndex, int maxResult) {

QueryResult<Product> qr = new QueryResult<Product>();

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<Product> products = new ArrayList<Product>();

int length = firstIndex+ maxResult;

if(length>hits.length()) length = hits.length();

for(int i=firstIndex; i<length; i++){

Product product = (Product)hits.data(i);

product.setContent(hits.highlighter(i).fragment("content"));

products.add(product);

}

qr.setResultlist(products);

qr.setTotalrecord(hits.length());

hits.close();

} catch (CompassException e) {

e.printStackTrace();

tx.rollback();

}finally{

if(session!=null && !session.isClosed()) session.close();

}

return qr;

}

public QueryResult<Product> search(String keyword, Integer typeid, int firstIndex, int maxResult) {

QueryResult<Product> qr = new QueryResult<Product>();

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<Product> products = new ArrayList<Product>();

int length = firstIndex+ maxResult;

if(length>hits.length()) length = hits.length();

for(int i=firstIndex; i<length; i++){

Product product = (Product)hits.data(i);

product.setContent(hits.highlighter(i).fragment("content"));

products.add(product);

}

qr.setResultlist(products);

qr.setTotalrecord(hits.length());

hits.close();

} catch (CompassException e) {

e.printStackTrace();

tx.rollback();

}finally{

if(session!=null && !session.isClosed()) session.close();

}

return qr;

}

}

//compass支持增量索引,社会上很多公司,他们的产品都没有实现增量索引,1>lucene版本比较低,不支持增量索引,2>要增量索引,技术要求稍微有点高

//(晚上 2-3,定时器,把索引文件删除,重新生成索引)实时性不强,在索引文件更新的时候,用户是访问不了的

以上基本都为讲解,下面是具体的开发步骤:

步骤一:

导jar:compass的两个文件,疑问logging文件一般我们已经存在了,lucene的六个文件

步骤二:

配置映射元数据:

设计实体,我们实体已经存在了,所以不用设计了,直接加注解

我们映射产品:

首先我们要加上搜索id

然后我们要分析一下那些是需要搜索的,哪些是不需要搜索的,但是需要显示在搜索结果中的。如果不需要显示也不需要索引就不管他

第三步:

我们对索引进行填、删、查

我们对产品进行保存的时候,我们就应该把索引也保持进去。

方式一:我们可以重写我们servicebean的保持方法。添加一个保存到索引里面去的方法。这样我们就存在一个问题,两个保存,有一个保存失败了,另一个保存就无法执行。就导致了数据不同,无法保证两种保存在同一个事物中

方式二:把compass集成到spring中,让他使用spring的事物管理功能。

在我们的spring中添加代码如下:

<bean id="compass" class="org.compass.spring.LocalCompassBean">

<property name="classMappings">

<list>

<value>cn.itcast.bean.product.ProductInfo</value>

<value>cn.itcast.bean.product.Brand</value>

<value>cn.itcast.bean.product.ProductStyle</value>

<value>cn.itcast.bean.product.ProductType</value>

</list>

</property>

<property name="compassSettings">

<props>

<prop key="compass.engine.analyzer.default.type">net.paoding.analysis.analyzer.PaodingAnalyzer</prop>

<prop key="compass.engine.connection">file://d:/index</prop>

<!-- 在内存中建立索引

<prop key="compass.engine.connection">ram://index</prop>

-->

<prop key="compass.engine.highlighter.default.formatter.simple.pre"><![CDATA[<font color='red'>]]></prop>

<prop key="compass.engine.highlighter.default.formatter.simple.post"><![CDATA[</font>]]></prop>

<prop key="compass.transaction.factory">org.compass.spring.transaction.SpringSyncTransactionFactory</prop>

</props>

</property>

<property name="transactionManager" ref="transactionManager" />

</bean>

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/partner4java/archive/2009/11/03/4763942.aspx

你可能感兴趣的:(spring,bean,Hibernate,搜索引擎,Lucene)