论坛首页 编程语言技术论坛

JavaEye3.0开发手记之四 - ruby的全文检索

浏览 18882 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-09-28  
在Java平台上面,lucene是众望所归的全文检索工具,lucene性能不俗,程序稳定,第三方扩展和分词算法众多,但是在RoR方面,就没有那么幸运了,JavaEye网站要做全文检索,怎么来解决全文检索的问题呢?

在ruby平台上面,全文检索有三个途径:

1、solr, acts_as_solr

solr是apache开源组织的一个项目,完全基于lucene的最新版本,在lucene的上层提供了一个基于HTTP/XML的Web Services。solr的发行包自己绑定了jetty6.0应用服务器,可以直接启动,成为一个独立的全文检索的web服务。

由于和solr的通讯方式是标准的基于HTTP的XML,所以你可以使用任何编程语言,Java,C++,Ruby,Python都不在话下。你通过向solr发送xml查询请求,让solr在后台运行lucene,返回结果也被封装为xml,当然你也可以让solr去做索引。基本上solr就是lucene的一个Web服务的封装。solr的优势在于为大规模的全文检索做了很多缓存优化,由于采用xml,也不限于客户端的种类。

RoR有一个叫做acts_as_solr的插件,封装了ruby对solr的访问,如果你喜欢用solr作为全文检索,acts_as_solr是一个不错的选择,他可以很方便的让你的RoR应用添加全文检索功能,考虑到lucene的稳定性,这个方案是一个相当不错的选择。

但是这个方案的缺点也是显而易见的,你的RoR应用所有的全文检索都要依赖后台再次向solr服务器发送web请求来获取结果,单个页面的执行速度肯定会受限于后台的跨http的web请求,这对于那些对全文检索功能依赖特别多的网站来说,恐怕很难接受。因此JavaEye3.0不采用solr方案。

2、sphinx

http://robbin.iteye.com/blog/122696

我已经在上一篇博客当中介绍了sphinx。我个人非常青睐sphinx这种独立的第三方全文检索服务器,而且能够和MySQL结合的很好,更不用说其优异的性能了。但是sphinx的缺点在于没有很好的分词扩展的接口,它是一个纯C开发的服务。这对于中文分词功能的支持来说,就很难实现了,因此不得不遗憾的放弃。

3、ferret

ferret是ruby平台模仿lucene的一个移植软件,但是ferret并非纯ruby实现,而是基本上用C编写而成,只有少量面向程序员的接口是ruby写的。ferret虽然和lucene很像,连API也基本一致,但是ferret的成熟度远远不及lucene,这表现在:

1) ferret不支持中文分词
2) ferret用C编写的,其索引格式和lucene不兼容
3) ferret的索引速度很慢,而且很不稳定
4) windows平台的ferret在search的时候会崩溃


尽管ferret有上面这些缺点,但是RoR平台可供选择的余地却不大,因此还是决定使用ferret。

------------------------------ ferret 分割线 ------------------------------

1、acts_as_ferret (AAF)

AAF是一个相当不错的RoR插件,封装对ferret的操作,但是经过我的考察,决定弃用AAF。这是因为AAF是直接绑定到model上面的,这会带来一些问题:

1) 每当model对象被insert/update/delete的时候,AAF会通过model的回调实时更新全文索引。在生产环境这是一个很可怕的事情,多个ruby进程同时更新索引,就会出问题。所以AAF索性提供一个DRB方式的ferret server让你在生产环境去用。

但即便如此,如果多个ruby进程同时更新索引呢? 考虑到ruby的green thread性能,drb server也很容易就被阻塞住。而且退一步来说,即便drb性能很好,每个全文检索请求都去发起一次ruby远程调用,恐怕也是很难接受的事实

2) AAF索引每条model记录,但我却不想索引隐藏贴,况且我的索引机制也不想绑定在model上面。

2、中文分词问题

如果只是简单的中文单字拆分,到不难支持,只需要利用RegexpAnalysis写个正则表达式去匹配UTF-8编码的中文就行了,目前JavaEye的全文检索就是这样处理的,貌似搜索结果还过得去。

但是如果要追求非常精确的搜索结果,则必然需要通过词典的最大匹配算法去进行中文分词。那就只能自己用ruby来写中文分词算法了,这个是留待我们今后要做的工作。

2、ferret的索引稳定性问题

JavaEye网站有8万topic,30万post,由于ruby本身性能不佳,ferret又不很稳定,在服务器上面直接做index,差点把服务器搞瘫了,所以此路不通。

由于全文检索并不需要很高的实时性,所以我们的解决办法就是每天晚上把数据库数据下载到本地的台式机上面,然后在本地台式机上面导入数据库,进行全量索引,然后在压缩打包上传到服务器上面去。这样每天的全文检索结果只会迟后一天的时间,基本上可以满足需求了。



   发表时间:2007-09-29  
solr比较好,http性能没有你想象那么低

而且全文搜寻压力并没有那么大的,大多数人都是看帖的

javaeye的全文搜索更加不大了,我基本不用,因为根本搜不出结果

往solr里面写数据可以做一个简单的队列服务器降低更新频率

而且你的做法是每天做一次完整的索引,那是不必要的,直接做差异就可以了,solr对修改支持非常好
0 请登录后投票
   发表时间:2007-09-29  
solr做的很好的,本来就是大站的产品,后来贡献给apache而已
0 请登录后投票
   发表时间:2007-09-29  
如果不是单纯的研究ror应用,把search做成java webapp,是不是更合适?
0 请登录后投票
   发表时间:2007-09-29  
一直用solr,感觉相当不错
javaeye选择ferret,值得商榷
从稳定性和扩展性两个方面看,还是solr更适合
至于性能,http的开销其实不大。搭建solr测试环境,也就小半天的事情,何不TDD?
0 请登录后投票
   发表时间:2007-09-29  
wainwen 写道
一直用solr,感觉相当不错
javaeye选择ferret,值得商榷
从稳定性和扩展性两个方面看,还是solr更适合
至于性能,http的开销其实不大。搭建solr测试环境,也就小半天的事情,何不TDD?


如果整个网站仅仅只是提供一个全站搜索功能而已,用solr没有什么问题。但是将来JavaEye3.0整个网站非常多的功能依赖全文检索,例如每个文章下面的相关文章功能,博客的相关推荐和类,wiki的相关链接,工作职位相关推荐,寻找同好的朋友等等......

如果整个网站的有一半的页面点击都需要发起后台的HTTP/XML请求的话,就要考虑这种方式还能不能采用了。
0 请登录后投票
   发表时间:2007-09-29  
zgd 写道
solr比较好,http性能没有你想象那么低

而且全文搜寻压力并没有那么大的,大多数人都是看帖的

javaeye的全文搜索更加不大了,我基本不用,因为根本搜不出结果

往solr里面写数据可以做一个简单的队列服务器降低更新频率

而且你的做法是每天做一次完整的索引,那是不必要的,直接做差异就可以了,solr对修改支持非常好


JavaEye的全文检索功能刚刚才支持,以前都是SQL查询,你现在可以试试看,效果肯定令你满意。

JavaEye的全文索引不单纯是索引内容,还需要根据帖子的点击次数,帖子投票的分值,帖子回贴的数量,发贴作者的等级来调整帖子的加权因子。即便很老的帖子,也会因为帖子点击次数,帖子投票分值变化而不断改变其加权因子,所以必须每天做全量索引。
0 请登录后投票
   发表时间:2007-09-29  
robbin 写道
wainwen 写道
一直用solr,感觉相当不错
javaeye选择ferret,值得商榷
从稳定性和扩展性两个方面看,还是solr更适合
至于性能,http的开销其实不大。搭建solr测试环境,也就小半天的事情,何不TDD?


如果整个网站仅仅只是提供一个全站搜索功能而已,用solr没有什么问题。但是将来JavaEye3.0整个网站非常多的功能依赖全文检索,例如每个文章下面的相关文章功能,博客的相关推荐和类,wiki的相关链接,工作职位相关推荐,寻找同好的朋友等等......

如果整个网站的有一半的页面点击都需要发起后台的HTTP/XML请求的话,就要考虑这种方式还能不能采用了。


明白你的意思了


那么选型的重点其实在于,是在后台整合搜索服务,还是在前台页面上整合搜索服务。



0 请登录后投票
   发表时间:2007-09-30  
zgd 写道


javaeye的全文搜索更加不大了,我基本不用,因为根本搜不出结果



哈哈, 一样一样 , 我都是这么搜索的, baidu or google 输入: site:www.iteye.com web 性能
0 请登录后投票
   发表时间:2007-09-30  
robin 可不可以说一下ferret 中文分词
GENERIC_ANALYSIS_REGEX = /([a-zA-Z]|[\xc0-\xdf][\x80-\xbf])+|[0-9]+|[\xe0-\xef][\x80-\xbf][\x80-\xbf]/
GENERIC_ANALYZER = Ferret::Analysis::RegExpAnalyzer.new(GENERIC_ANALYSIS_REGEX, true)
acts_as_ferret({}, { :analyzer => GENERIC_ANALYZER })

用这种方式。貌似可行。但只要多刷新几次。服务器就会停掉
c:/ruby/lib/ruby/gems/1.8/gems/activesupport-1.4.1/lib/active_suppor
odule/inclusion.rb:4: [BUG] Segmentation fault
ruby 1.8.5 (2006-08-25) [i386-mswin32]


This application has requested the Runtime to terminate it in an unu
Please contact the application's support team for more information.

怎么解决呢
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics