Loading...

Tag Archive for 'rails'

    AD: 子非鱼母婴社区 | 猛买 | Jobsdigg | 很棒的男装店

rails中使用Ultrasphinx+Cache_fu加速全文检索

前段时间我写了在Rails中使用Ultrasphinx代替acts_as_ferret插件来做全文检索,相应地也会用sphinx取代ferret。具体的做法可以看这篇文章。 先明确下概念,sphinx是类似lucene的一个全文检索实现,而ultrasphinx是rails的插件,有了ultrasphinx,我们可以方便地使用sphinx进行索引、检索。 但我在使用的过程中发现,每次进行检索之后,ultrasphinx都会调用一次或多次find_all_by_id来获得符合条件的ActiveRecords。但如果在项目中用了cache_fu之类的插件,使用memcached做对象缓存后,ultrasphinx依然没法使用缓存。为了避免这成为性能的瓶颈,我开始探索,是否可以让ultrasphinx和cache_fu合作,让搜索的结果也能使用memcached的缓存。 查了一下,ultrasphinx的作者还真的提供了这个口子,虽然他也不确定是否会有人用。打开/vendor/plugin/ultrasphinx/lib/ultrasphinx/search/internals.rb,找到一个叫reify_results的函数,里面有这样一段: finder = ( Ultrasphinx::Search.client_options['finder_methods'].detect do |method_name| klass.respond_to? method_name end or # XXX This default is kind of buried, but I’m not sure why you would need it to be configurable, since you can use ['finder_methods']. “find_all_by_#{klass.primary_key}” ) 也就是说,只要设置Ultrasphinx::Search.client_options['finder_methods']的值,就可以自定义查找ActiveRecord所使用的方法。正巧,在使用cache_fu插件后,有一个get_caches可以达到我们的目标。 于是在config/enviroment.rb中增加一行: Ultrasphinx::Search.client_options['finder_methods'] = ['get_caches'] 然后重新启动应用。试着搜索一下,不出意外会看到一个出错的提示。这里是因为get_caches函数返回数据的格式和find_all_by_id有点小区别。find_all_by_id返回的是一个ActiveRecord的数组,而get_caches返回的是一个数组的数组。只消在上面的internal.rb中的reify_results函数里,找到下面这个地方: records.each do |record| record = record[1] if record.is_a? Array [...]

[分享]Rails中ultrasphinx全文检索的使用(对象间关联的处理)

关于ultrasphinx的在windows上的安装和简单修改,请看这篇文章:深入探索:Windows+Rails+中文全文检索。 在上一篇文章里,我们初步可以让sphinx、ultrasphinx以及libmmseg正常地工作了。但是这些还不够,因为在实际的使用中,rails的AR之间会有很多关联。比如用户搜索一本图书时,可能希望也搜索它的作者,但如果图书和作者放在两个表呢?我们需要在ultrasphinx中处理这些关联。我在学习时能找到的资料都是英文,今天写这篇文章,希望能对英文不好的同学们有些帮助。 在Rails项目的ActiveRecord定义中,我们通过is_indexed函数告诉ultrasphinx这个Model需要进行索引的字段信息,最简单的写法: class Book< ActiveRecord::Base is_indexed :fields =>[:title] end 这里就表示将title属性交给ultrasphinx去做索引。但如果是一些关联的对象,该怎么做呢?如果使用acts_as_ferret,可以比较灵活,因为索引是绑定在Model的。而ultrasphix的思路是把索引和model独立开来,在特定的时候,使用SQL语句从数据库中获得数据,然后异步生成索引。 那么,如果要加入关联对象的字段,该怎么办呢?上面已经说到,信息是从数据库里得到,然后异步进行索引的。也就是说我们需要进行连接查询,然后获得相应的字段——大体思路就是这样,ultrasphinx提供了一些办法尽量避免让你编写复杂的SQL。 返回刚才的例子,假设每本图书都属于一个出版社,这是一对多的关系。出版社用Press来表示,表示名称的属性是name。我们需要让用户可以一起检索到出版社的名字,ultrasphinx中提供了一个”:include”来帮我们做到: class Press < ActiveRecord::Base has_many :books end class Book < ActiveRecord::Base belongs_to :press is_indexed :fields=>[:title], :include=>[{:association_name=>'press' , :field=>'name' , :as=>'press_name }] end 保存后重新运行”rake ultrasphinx:configure”,将在RAILS_ROOT/config/ultrasphinx/目录生成一个新的development.conf。如果有兴趣可以打开看看其中的SQL生成成了什么样子,不过还是建议你别看了,继续看文章吧。之后运行”rake ultrasphinx:index”,就会重新生成索引,将出版社信息也增加进去。可以再运行”rake ultrasphinx:daemon:start”启动伺服器,测试的办法请看这篇文章,不再赘述。 上面交代了belongs_to的时候的处理方式,如果是has_many呢?ultrasphinx为提供了另一个”:concatenate”。假如每本书(Book)都有一些描述信息(Info.content),我们想把这些信息也一起加入到索引中。 class Info < ActiveRecord::Base belongs_to :book end class Book < ActiveRecord::Base belongs_to :press has_many :infos [...]

深入探索:Windows+Rails+Sphinx进行中文全文检索

先说点题外话,以后大家买独立服务器的时候,还是买linux的吧。如今这么活跃的开源社区为linux贡献了好多柴火,而相应的软件在windows实在发展得缓慢。要是我当初买了linux服务器,以前和现在都能少许多烦恼,今天的“深入探索”,根本就用不着。 事情是这样的,我手头的一个项目里,打算用rmmseg+ferret+acts_as_ferret搭配起来做全文检索。一直也相安无事,直到我今天决定放到生产环境试试看。这一试不要紧,发现DRB服务器启动不起来,提示的是”fork() funtion is unimplemented on this machine”。windows上哪里有fork啊,我顿时欲哭无泪。如果不用DRB的话,就也不能用acts_as_ferret了(原因请看robbin的这个帖子)。 恩,这时我并没有灰心,因为我在前几天看到了另一个解决方案,用的是sphinx,狮身人面。其中有windows版本的安装: 在Windows上安装 在Windows上为Sphinx打补丁、编译、连接libmmseg要比在Linux上做这些事情麻烦得多,而且大多数Windows上的开发人员都没有自己编译开源软件的习惯,幸好李沫南已经做了一个安装包: http://www.coreseek.com/ft/csft_setup_2.5.1.exe 执行这个安装包即可安装Coreseek的Windows版,假设将Coreseek安装在D:\CsFullText25 将D:\CsFullText25\bin加入到环境变量PATH中,以便以后在命令行能够找到Sphinx提供的各种工具。 安装Ultrasphinx Sphinx在Linux和Windows上都已经安装好了,我们可以通过一个Rails程序来做一下测试。 假设我们原先有一个Rails应用thought_log cd thought_log ruby script/plugin install -x svn://rubyforge.org/var/svn/fauna/ultrasphinx/trunk 若这个Rails应用尚未提交到SVN中,或者使用其他版本管理工具,则使用 ruby script/plugin install svn://rubyforge.org/var/svn/fauna/ultrasphinx/trunk 注意,执行这条命令前需要先安装好SVN for Windows(不是TortoiseSVN)。 当我按部就班执行到红色的那一步,命令行里提示我该svn不存在。我直接打开,也是404错误。这个最重要的rails插件,在我要安装的时候,居然消失了。 百般无奈,只好放一放,出去打个电话。电话回来,突然有了灵感,尝试用”gem install ultrasphinx”,居然安装成功了,不过是作为gem。没关系,我跑到gems目录下,找到ultrasphinx的文件夹,整个复制到rails项目的vendor下面,同时把文件夹改名为ultrasphinx。 果然,gem安装的ultrasphinx就是那个消失的rails插件,不晓得为啥从插件变身gem了。但是探索还没有结束: 为了在Windows上正常使用Ultrasphinx,需要为Ultrasphinx打一点补丁: 修改vendor/plugins/ultrasphinx/tasks/ultrasphinx.rake 在文件最后加入: def os_path path if RUBY_PLATFORM =~ /mswin32/ path.gsub!(‘/’, ‘\\’) end path end 然后将其中的: “searchd –config [...]

三大范式

晚上睡前在robbin的blog翻看,看到以前没多留意的一篇关系模型和对象模型方面的文章。文章是从一本《MySQL 5 权威指南》说起的,我也读过这本书,确实,对其中三大范氏的描述很感兴趣(比我们在课上讲得深入多了),但没有像robbin思考的这么深入。 摘录部分robbin的文章: 关系模型和对象模型存在概念上的阻抗不匹配,但是在关系数据库的存储模型上是一致的,无论你从关系模型的三大范式理论出发,还是从对象模型的ORM理论出发,最终一定会得到一致的数据库表设计。 嗯,这个容易理解,但做数据库设计的时候,难免会犯这样的毛病: 传统的数据库应用软件开发,程序员很难从符合三大范式的数据模型当中获得有效的查询性能。符合三大范式就意味着数据库表会拆分的很细,表间关联很多,统计 分析查询就不可避免的导致n张表的联合查询,在没有有效的应用层缓存的情况下,这种查询无可避免的性能低下。这使得程序员宁肯违背三大范式,而选择查询性 能优先的数据库设计。 但下面这群数据,让人惊讶: JavaEye使用了Rails的ActiveRecord ORM,表设计符合三大范式,所有页面都是动态页面,要对数据库发送大量查询,很多Web页面至少要向数据库发送50条以上的SQL语句。根据对数据库和 Memcached Server的统计数据表明:JavaEye网站平均每秒向数据库发送140条SQL语句,平均每秒向Memcached Server发送250次缓存查询,缓存命中率大概为85%,也就是说缓存服务器要比数据库服务器繁忙将近一倍,而Ruby应用程序的数据有60%是来自 Memcached Server,而只有40%是直接来自MySQL的。 WP每个页面查询几十次数据库,我自己都有点心疼服务器,这么看来是符合了三范氏设计的结果。WP如果可以出来类似rails中的缓存机制就好了(貌似Rails中的缓存,也不是那么完善)。上面的数据很给我信心,规范的设计+适当的缓存策略,应该可以获得好的性能。 最后,我的结论就是对象模型和关系模型在数据库存储上不存在阻抗不匹配,面向对象的程序设计和面向数据库的程序设计应该是一致的,而不应该是对立和冲突的,请不要把面向对象和面向数据库对立起来,不是他们对立,而是你不了解什么才是真正良好的设计。 UPDATE:这些东西,也只有在真正有过实践之后,才能有体会。若是没有实践,推测是推不出来的。

荐书(1)

看到Fenng说今天(or 昨天?)是世界读书日,正好最近都打算写写自己看的书。内容比较多,所以打算分2、3天来写。今天先写写技术方面我最近读的一些书,明天打算写一下其他方面的书。 最近颇为关注Ruby和Rails,学得也比以前更深入。 Ferret 这本书是讲ferret的,是一个ruby下面Lucene的移植(现在的数据已经不和lucene兼容了)。国内没有Ferret影印版或者中文版,我看的是英文版CHM电子书,有兴趣的朋友可以搜一下。这本书是ferret的作者写的,所以谈得很不错。不过要用ferret来索引中文,分词方面推荐使用浙大pluskid写的Rmmseg。PS:看到pluskid谈到学软件工程,没准和我一样是05级的呢。 Ruby Cookbook (影印版) (中文版) 以前推荐过第二版的Web开发敏捷之道 ,不过这本ruby cookbook更侧重谈ruby。我想肯定有这样的人,在开始照着别的书书写基于rails的程序,自己却不知道为什么要这么些。从这本Ruby Cookbook中不难发现,ruby很多时候都是轻快而便捷。书中的一些示例也很不错,比如用贝叶斯过滤器进行文本分类(这个地方需要说一下,可能对中文来说得搭配相应分词器),比如创建PDF、编辑图片。 Rails Cookbook (影印版) (中文版) 两本都是cookbook,不过这本当然是以rails为主。和 Web开发敏捷之道不同的是,这本书并没有一开始花大篇幅做例子。可能已经不需要用示例来说明rails是多么激动人心了 。我关注这本书里较多的是restful development 、performance 和 rails的部署,特别是部署这部分。我没有什么经验,而rails的部署方式也太多了(apache基本被淘汰,后端用Fastcgi或是mongrel争论不休)。下个月可能会做好手里的第一个rails项目,正好用到书里面的知识。 Ruby for Rails 这本在卓越亚马逊只找到了中文版,算是比较早的谈ruby的书。厚度上没有两本cookbooks厚,但是读起来感觉不错。比起ruby cookbook谈了更多rails,比起rails cookbook谈了更多ruby 打算读的书: 算法导论 虽然以前也在校ACM集训队呆过,但总觉得自己在算法方面还不够好。说实话现在很多时候算法已经被数据库这些东西给解决了,可还是需要自己有所了解。我学东西一向的思路是明白道理就好,真正用的时候还可以查。

在Dreamhost部署Rails

今天写了一个小Spider,用rails做的。为了一个sipder而弄了这么老大一个项目实在不是本意。最初只是觉得用Rails写起来会比较快,现在看来,如果考虑上效率,还是用PHP更划算。 以前没有试过在Dreamhost部署Rails应用,今天就尝试了一下。其实也没那么难。Rails应用中,网站更目录是public/,于是我们需要在Manage Domain中添加网站时,把根目录定位到这个public/。别忘了勾选fast cgi support ——虽然没看到这个的效果,但fast CGI肯定会比CGI快阿。当然,还需要在database.yml中指定对应的数据库配置,这些不再赘述了。 之后,通过在Manage Domain处添加的域名,如果可以打开网站,说明一切正常;如果打不开,那就需要再检查一下上面那些设置是否正确。我后来试了试在服务器上运行了Webrick,然后通过http://www.blogkid.net:3000也可以正常访问——这个时候用哪个域名已经不重要了,只要是指向这个服务器的域名,3000端口就是我的rails程序 DH运行Rails程序还不稳定,经常会初现rails程序没有正确启动的错误。也不能对它有太多要求吧。最近因为牛扑流量太大(加上爬虫每天也才15万次请求),DH不停联系我说数据库压力大,禁用了好几个表。

如何在Rails中实现图片上传

早就想写的,不过今天才有点时间。最近多线繁忙,好不充实。 在Project Lucas中需要做图片上传的功能,参考了《应用rails进行敏捷web开发》这本书,果然就成功了。我写了一个详细的例子在这里:http://www.googlecto.com/2008/02/18/how-to-upload-pictures-in-rails/

Rails中查找记录的异常处理

下午又在折腾一个Rails项目,遇到一些莫名其妙的问题,不过好在后来都莫名其妙地被我搞定了。不过又有一些心得,觉得快可以为这个blog单独开一个分类了。 众所周知,在Rails中查找记录可以方便地使用find方法,而假如对应数据库中有一个name字段,也可以使用find_by_name来通过name值查到记录。但当记录查不到时,两者就有了不同行为。 在irb中这样尝试: >> User.find(3) #id为3的用户是不存在的 ActiveRecord::RecordNotFound: Couldn’t find User with ID=3 from /var/www/Lucas/vendor/rails/activerecord/lib/active_record/base.rb:1031:in `find_one’ from /var/www/Lucas/vendor/rails/activerecord/lib/active_record/base.rb:1014:in `find_from_ids’ from /var/www/Lucas/vendor/rails/activerecord/lib/active_record/base.rb:419:in `find’ from (irb):13 我把第一行关键部分加粗了,可以看到,在没有找到对应记录时,Rails抛出了一个”ActiveRecord::RecordNotFound”的异常。在进行异常处理时,只要用rescue ActiveRecord::RecordNotFound 就可以捕获这个异常。 而再在irb中进行下面的尝试: >> User.find_by_name(3)  #name为3的用户也不存在 => nil 依然不会找到记录,却没有任何异常,返回了nil。自然,下面的处理也不能用刚才的方法,而要检查返回的对象是不是nil。今天下午,就被它困扰很久。关键时刻,还是irb能说明问题。 还有logger也是个好东西,它的用法比较简单,大家可以网上搜搜。

Aptana

因为近期的Project Lucas要用到Rails,可是手里实在没有趁手的工具。工欲善其事,必先利其器,找个好工具还真难。 之前说了Scribes,确实是个值得推荐的东西。但有两个问题:一是它会打开很多窗口,每个窗口只能看一个文件。要知道,Rails项目的文件尤其多,它的窗口会堆满任务栏,有时还会死。另一个问题是我键盘上唯一的CRTL键坏了,于是那些便利的快捷键根本没办法用了。所以我放弃了Scribes回到Gedit。而Gedit一个很大的毛病就是每次编辑文件都会自作聪明搞一个备份,要把人烦死。后来,我找到了Aptana。 准确地说是找到了RadRails。Aptana最初是找来做javascript开发的,装好后发现它的界面和eclipse太相似了,肯定有着某种关联,可是我也不知道到底它们是什么关系。RadRails是aptana的一个插件,猜测也能给Eclipse用。我在aptana上装好了RadRails,用了一下,感觉不错。 Aptana对javascript的支持也非常好,昨天晚上和今上午我做了一个用来编辑链接的“InPlaceEditor”,对里面的代码提示、自动缩进兴奋不已。 不好的一面是,IDE很容易让人产生依赖。本来好多事可以我们自己来做的,比如在命令行里生成rails控制器、启动服务器,可是现在都在aptana中可以搞定了。如果不是要用Firebug调试js,里面Web浏览器也可以让我们省了打开Firefox。Aptana还有个不好就是暂时不能输中文,我也暂时用不到。如果需要,应该可以通过这种方式搞定的。

OVER

最近不大开心,总觉得被折磨了好久,但明白只是因为那个软件工程的作业。不是我功利,但是做那么一个作业实在对我没什么益处,在白白浪费时间。又想起今年考软设之前的情景,不想看软设,但也不能干别的事情。 好在软件工程的作业在今天有了个了结。上午一边担心着某人的机票发着短信,一边给老师讲着我没有做完的作业。虽然没做完,用rails还是做了很多,周围同学们的啧啧声都听在耳朵里。老师去看下一组作业后,真的有如释重负的感觉。 不是完全没收获,也积累了不少用Rails的经验。当然,接下来的另一个项目也要用Rails来做了。于是今天在折腾Rails的IDE。之前推荐的这个 ,很容易打开很多个文件窗口,最后搞死掉。而一个rails项目的文件本就很多。后来找到了RadRails。 之前用Gedit和Scribes都是闹着玩,现在可得动真格了。