一般情况下,你也可以使用hibernate本身提供的DetachedCriteria类来进行多个字段的查询,从而实现全文检索的效果。参考的代码如下:
Junction junction = Restrictions.disjunction()
.add(Restrictions.like("website", search, MatchMode.ANYWHERE).ignoreCase())
.add(Restrictions.like("company", search, MatchMode.ANYWHERE).ignoreCase())
...
这样可以对表中的所有字段来查询。然而, hibernate在执行这种查询时使用HQL(最后都是使用SQL标准查询语言),这样其实还不是真正意义上的全文检索,而且这种查询会随着字段数量的增加而降低性能。
hibernate意识到这一点,面对互联网搜索引擎的强大检索性能的挑战,高效而易于实现的全文检索是开发数据库应用程序的一个重要需求。hibernate推出了基于lucene search的全文检索集成。
lucene search是apache一个有名的全文索引引擎,其主要的功能是做内容索引及查询服务。详细的技术细节可以参考apache lucene网站,这里不作详细解释了。
要在使用了hibernate框架的项目里使用hibernate search,可以按照以下几个步骤进行:
第一、获得类库及配置
Java 版本为1.5 以上, hibernate 3
你可以到hibernate search官方网站上下载其最新的api (目前版本是3.1.0 GA)
要使用hibernate search,需要在代码中使用到Java1.5支持的Java声明技术,所以你要下载hibernate annotation,这个是hibernate的声明类库。
另外,如果你的Java对象里使用了高级的hibernate集合影射,还需要J2EE包的annotation。
把这些类jar文件放到你的开发、编译及运行环境中。清单如下
# hibernate-search
3.1.0.GA
#hibernate-annotations
3.4.0.GA
#hibernate-entitymanager
3.4.0.GA
#solr-common 可选
1.3.0
#solr-core 可选
1.3.0
#lucene-snowball 可选
2.4.0
接下来配置一下hibernate的properties,有两个基本属性
property name="hibernate.search.default.directory_provider" value="org.hibernate.search.store.FSDirectoryProvider"
property name="hibernate.search.default.indexBase" value="/var/lucene/indexes"
*这个是指定lucene引擎在索引是产生的索引文件的存放位置
如果你使用了spring框架,你可能需要在对象被创建、更该或删除后hibernate自动更新lucene的索引,你还需要向spring框架里添加event listener,下面是所需的配置参考代码
这样,基本的环境配置就完成了,可以进行下一步编码的调整了
第二、调整索引编码
要使hibernate search可以索引对象的数据,你需要对hibernate的实体对象entity进行索引声明调整,以一个简单的带集合影射的contact bean为例
@Entity
@Indexed
public abstract class AbstractBean{
private Integer id;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@DocumentId
public Integer getId() {
return id;
}
... ...
}
@Entity
@Indexed
public class Contact extends AbstractBean{
@Field(index=Index.TOKENIZED, store=Store.NO)
private String phone;
@Field(index=Index.TOKENIZED, store=Store.NO)
private String fax;
@Field(index=Index.TOKENIZED, store=Store.NO)
private String mobile;
@Field(index=Index.TOKENIZED, store=Store.NO)
private String zipCode;
@OneToMany(fetch = FetchType.EAGER)
@Cascade(org.hibernate.annotations.CascadeType.ALL)
@IndexedEmbedded
private List
}
@Entity
public class Email extends AbstractBean{
@Field(index=Index.TOKENIZED, store=Store.NO)
private String email
}
请留意@index, @Field, @OnToMany, @Cascade, @IndexedEmbedded等,hibernate (lucene) 提供针对不同搜索内容的index声明,用于优化索引的内容以及查询的结构。
如果不需要特殊索引要求,可以保存这些声明调整,进行下一步搜索工作。
第二、使用全文搜索
也许你在引入使用hibernate search功能前,系统的数据库已经存储了一定数量的数据了,为了能够搜索到已有的数据,必须手动索引现有数据,做法如下:
public Integer reindexFullTextSearch(){
FullTextSession fullTextSession = Search.getFullTextSession(session);
Transaction tx = fullTextSession.beginTransaction();
List
for (Contact contact: contacts) {
fullTextSession.index(contact);
}
tx.commit();
logger.info("Contact reindex fulltext search results: "+contacts.size());
return contacts.size();
}
这个方法可以触发hibernate search对现有的contact数据做索引,在hibernate环境中运行这段码,你会在之前配置的索引目录下看到索引文件的更新。当然你打不开它,因为是二进制文件。
完成这步后,因为你在配置hibernate search时定义了event listener,以后当对象被创建、修改或删除时,都可以自动地更新索引了。这听起来不错,那要怎样搜索呢?请看下面的代码:
public java.util.Collection
FullTextSession fullTextSession = Search.getFullTextSession(this.getSession());
Transaction tx = fullTextSession.beginTransaction();
// create native Lucene query
String[] fields = new String[]{"id", "phone", "fax", "mobile", "zipCode", "Email.email", };
List results = null;
try{
MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, new StandardAnalyzer());
Query query = parser.parse( keyword );
// wrap Lucene query in a org.hibernate.Query
org.hibernate.Query hibQuery = fullTextSession.createFullTextQuery(query, Contact.class);
// execute search
// paging (optional)
if (start!=null && limit!=null) {
hibQuery.setFirstResult(start);
hibQuery.setMaxResults(limit);
results = hibQuery.list();
}else{
results = hibQuery.list();
}
logger.info("Contact fulltext search results: "+results.size());
}catch(Exception e){
logger.error("Failed to run fulltext search: "+e);
}
tx.commit();
return results;
}
你会看到,关键字keyword会被首先分析,然后进行查询。缺省情况下关键字keyword的分析是StandardAnalyzer,这个关键字分析是全文检索的重要功能,如果需要针对不同的语言做分析,可以选择不同的分析器。
在hibernate环境下运行这段代码,你可以得到返回的搜索结果。
No comments:
Post a Comment