Wednesday, August 14, 2019
Friday, April 17, 2009
Hibernate search 实践[1]
一般情况下,你也可以使用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环境下运行这段代码,你可以得到返回的搜索结果。
Tuesday, March 3, 2009
ClientVision CRM wiki 维基文档

ClientVision CRM wiki is in progress. You could see it on
http://wiki.clientvision.cn
ClientVision is a CRM product which is customized for Recruiting business. Started from 2006, this java web baseed application use spring framework + hibernate, and dual database, PostgreSQL and eXist XML DB.
To use dual database is because it is time for energy-saving and environmental protection. Use XML database to save development resources and efficient for some user cases. This obviously save customer's budget under this economic crisis.
ClientVision CRM的维基文档正在编写中. 你可以在输入下网址查看
http://wiki.clientvision.cn
ClientVision (还没有中文名)是一个专门针对猎头/人力资源服务公司的客户关系管理CRM软件。这个产品开始于2006年,技术架构使用spring框架+hibernate,同时采用双数据库-“混合动力”,PostgreSQL和eXist纯XML数据库,都是开源项目。
之所以使用“混合动力”是因为现在需要环保与节约。使用XML数据库可以节省开发工程师的人力,并在某些应用情况下提高效率。这自然可以在经济危机下节省客户的开销。
Thursday, December 18, 2008
Extjs与XML的结合应用,组件化的web界面开发
传统的桌面软件的界面开发都采用与开发工具整合(IDE)的界面组件设计器来完成软件界面的设计与实现,并已经有大量丰富的设计工具软件和资源可以使用。使开发人员的界面开发工作变得容易与高效。
Web界面开发有别于传统的桌面软件界面开发,其中涉及的标准与技术很多而且复杂,拿一个JEE的Web界面开发所使用到的技术为例,其中就包含以下的技术:
HTML/CSS, Javascript, DHTML, JSP/Servlet, XML, 不同浏览器的兼容性等,
这些技术本身都各不一样,需要全部掌握才可以熟练开发;而且,到目前为止,还没有那一个集成开发工具可以把这么多的技术成功融入到可以独立使用的组件里,象桌面开发那样。
不过使用AJAX技术的一些javascript框架的发展使得Web界面开发也可以组件化的需要可以得以满足了。这就是
Extjs与XML的结合应用,组件化的web界面开发
Extjs 是一款优秀的应用Ajax的javascript组件框架,这款框架是一个开源的框架,前身来自Yahoo的UI开源javascript库。而Extjs的开发者把它作进一步的发展,使得这个javascript的框架与UI的HTML界面元素结合并提供更丰富的组件化开发。要取得这个框架或者详细的文档资料,可以访问其网站 http://extjs.com
XML就不作详细介绍,这是一个互联网的信息媒介标准,并日渐大量使用在现在的信息系统开发中。这里要介绍的是如何使用XML作为数据的传输格式与组件化的Extjs框架结合使用,使得Web界面的开发效率、性能与功能都得到提高。
我们看一个十分普遍而简单的常见例子,开发一个城市名称下拉菜单
XML数据
=================================
<locations>
<location><key>1</key><value>北京</value><location>
<location><key>2</key><value>上海</value></location>
<location><key>3</key><value>广州</value></location>
</locations>
Extjs 的数据存储
=================================
locationStore = new Ext.data.Store({
// load using HTTP
url: 'util.html',
baseParams: {act:'loadValueList', id:'location'},
reader: new Ext.data.XmlReader({
totalRecords: 'results',
record: 'listItem'
}, [
{name: 'key'},
{name: 'value'}
])
});
Extjs 的下拉菜单组件
=================================
localeCombo = new Ext.form.ComboBox({
mode:'local',
store: locationStore,
value: 'en',
hiddenName: 'locationId',
valueField: 'key',
displayField:'value',
width: 130,
triggerAction: 'all',
forceSelection:true
});
这是一个非常简单的例子,把城市的名称显示为一个下拉菜单,供用户在web的表单里选择。这个简单的例子是为了演示使用Extjs可以把一个下拉菜单的组件分为数据、模型和视图,跟Web的MVC框架是一个道理,不过这是在客户端。
这样做可能会使得客户端的组件开发变复杂了,但好处是可以把组件的显示与数据绑定分开。我们知道web界面的开发的一个最头痛的问题是如何使相同的一个组件在不同的浏览器下能够显示相同的特性,具有相同的行为。Extjs把数据绑定抽离出来,的确解决了这个问题,同时带来的好处是数据与组件显示的可重用。
这是开发专业的web界面与富客户端rich-client应用程序的必须。
Extjs目前支持两种格式的数据,JSON与XML,JSON是JavaScript Object Notation, 就是一种用于JavaScript脚本的数据传输处理格式。这种格式比XML简单,处理起来相对容易,也是Extjs推荐的。不过使用XML就更为标准。
Sunday, December 7, 2008
发布基于OpenCms网站内容管理系统的网站
www.tongtaipawn.com 广东省通泰典当行
该网站使用OpenCms7 开发, HTML采用div+css的代码布局以便更容易控制样式和对搜索引擎友好
网站提供了一个方便典当行发布黄金和白金的典当价与断当价格的工具,一个访客与典当行的问答论坛。这两个功能可以帮助典当行把最重要的业务信息及时地与用户通过互联网进行交流。
Sunday, November 2, 2008
database design - Key Value Pairs
As we know there is some key value pairs (KVP) using in database design. And it is very common in lots of projects. I forget what the actually purpose is at the moment. But I feel that some KVP design in commercial software product will make the maintenance and development a pain.
The reason is simple, developer needs to convert the key to value in SQL or Java class. Here is a sample.
KVP for language
1;"English"
2;"French"
3;"German"
4;"Spanish"
5;"Japanese"
6;"Russian"
7;"Korean"
8;"Mandarin"
9;"Cantonese"
10;"Other"
For the language storage, we save key in module table like language skill, candidate master. When we retrieve the data for candidate or language skill, we need to convert the language key to value so it displays the right text on browser. On the other side, when user searches data with language, like “German”, it needs to convert “German” to “
For this case, I think the KVP is useless. It makes search more complicated.
I remembered that I discussed with some experienced DBA about this long time ago. The one purpose of using KVP in SQL database design is to optimize the storage of data, to save hard drive space. Now a truth is hard drive and memory becomes much powerful and large than before. I think software design is stepping out the time of hardware bound so developer can focus on software creativity than saving hardware resources.
Of course, it doesn’t mean we just throw all KVP in database design. But we had better to keep in mind to change the software design from computer oriented to business oriented.
Monday, September 22, 2008
伴随网络成长的一代
现在青少年的房间里大多会出现这样的场景:开着电视和电脑,iPod的音量调到最大,作业本打开着,同样打开的还有电脑屏幕上的许多“窗口”,google网站显示着搜索结果、聊天页面正在闪烁。这就是现代青少年“做作业”的情景。
“一心多用”的本领是新一代人的集中特点。这是看电视时“跳过广告的一代”,他们将这一本领衍生到了从手头的一件事情跳到另一件事情,学习、工作、人际交往、等一样也不耽搁。他们的父母和老师们总是抱怨:“这些孩子好像从来不会从头到尾地完成一件事情,不会坚持不懈。要他们对一件事情保持长久的兴趣或承诺很难。”
1984年到到1995年间出生的孩子现在年龄在12岁至24岁之间。他们的生活离不开电脑,他们与电脑差不多时间诞生,并在互联网的陪伴下成长。尽管这待人因地域不同而有一些差别,却已经成为一种全球现象。
这一代的年轻人更青睐时间灵活,团队优秀、气氛良好的工作。他们很少对所在的公司从一而终,不喜欢受约束,善于抓住机会。因此,他们会毫不犹豫地辞职去休假,然后开始期待已久的旅行或者参加一项对他们来说更刺激的活动。
与网络亲密无间
现在很多年轻人习惯在聊天框中写上一个小提醒,例如“我在吃饭”、“我去洗澡”等,总之永远也不会与对方失去联系。因此,这一代年轻人“需要时刻保持联系”,这与之前几代人的隐私观念大相径庭。他们通过博客毫不费吹灰之力地展现自己,尤其是照片博客。在这一代人的生活中,电脑取代电视的趋势逐渐明显。面对电视的被动性,这些年轻人更愿意选择具有互动性的新兴传媒。