Archive for the ‘Ruby’ Category

 
May
01
Posted (xurenlu) in Ruby on 05月-1-2008

最近为ruby,ruby on rails的灵活和魔幻而着迷。爽。
上上周一个同事给我们介绍了自然语言处理的一些知识,觉得很不错。事实上虽然是雅虎公司的一名工程师,但是因为我不是搜索/邮箱/平台研发这些部门,基本上没有接触到比较深一点的东西,也许对于这些部门来说很简单的东西,对于我来说还是很难以理解的。
课后自己去找了些东西看了看,然后有这样一思路,可以用来构造一个垃圾站。
基本思路是:
1.首先我需要一个spider.这个spider由两个部分完成,第一部分是由一个feed管理程序来不停地从网上读rss回来,第二部分是常规spider,跟nutch什么的spider无异.
2.第二部分是预处理。这一部分包括:纯文本化、去垃圾。
3.第三部分是运算:分词,关键词提取,提取相关文章。
4.热点呈现,网站部分。
具体实现:
rss 的spider要简单一些,但是根据抓回来的内容,也是很多质量不高的种子。比如新浪新闻的rss基本没有正文,而有些feedsky的种子后面跟着一个小尾巴(广告),需要处理。
对于没有正文的,很简单,将之平均长度算出来,如果某个种子的平均长度都很短,就将这个种子丢弃。
对于很多内容不咱的,但是广告链接一大堆的,也有办法:先纯文本化,一个文档就细化为一系列的段。html标签有的去掉了,有的换成空格了.这时将段按空格分组,如果没组长度都很短,即文章内容中若是大量充满着html标签,这样的多半是广告或是垃圾链接。
比如这一段:

  1. 2006-09-11   charon 写道  我现在对这类动态语言的非本质实现抱很大的怀疑态度。 最近除了这个新闻以外,IronPyton(python的.net版本)1.0也发布了。但看了一下,感觉虽然不是特别差,也是差得可以。也许这是给那些熟悉.net同时又想找一个动态语言的人一个选择? 两个语法相同但是标准库有差异(jruby可能语法上也略有差异),支持库有重大差异的语言,还能算是一个语言吗? 当年不论出于什么原因,Sun对于MS污染java的行为举起了大棒,现在这几个开源社区的动态语言,却纷纷搞出这么些方言来,不好说阿。   IronPython和JRuby可能还是不太一样的。dotnet平台实际上提供了自己统一的dotnet fraemwork类库,所谓不同的编程语言支持,更像是一种语法糖衣而已。但是JRuby其实实现了大部分ruby自己的库,用JRuby并非仅仅用一个ruby语法而已,关键是ruby本身的方便的库和rails框架,至于Java库的支持,只是辅助了。  Sun对JRuby的支持表明了一种态度,这种态度是承认ruby在企业快速开发方面的优势,而对ruby提供更好的支持。而Microsoft支持的IronPython更像是用python语法写C#程序那种感觉,换汤不换药。     charon
  2.                  robbin     浏览: 1653543 次  性别:   来自: 上海      详细资料    搜索本博客        博客分类    全部博客 (119)    杂感 (38)    Java (27)    Ruby (31)    System (5)    JavaEye (19)      我的相册       游乌镇  共 33 张     其他分类    我的收藏  (19)   我的论坛帖子  (4506)   我的精华良好贴  (97)     最近加入圈子    JavaEye沙龙    广州JavaEyer饭局群    Ubuntu For Fun    JavaEye水源    英语学习      链接    javaeye      存档    2008-04  (2)   2008-03  (6)   2008-01  (7)   更多存档...      最新评论    Warp framework - 一个相 ... 
  3. 当然新的东西是可以尝试的,我 ... 吧?
  4.                   -- by dhxyu    总结一下大家对JavaEye网 ... 
  5.                   支持`~~
  6.                   -- by hgz123    关于JavaEye网站未来发展 ... 
  7. javaeye前途无量! 今天认真看了这篇文章,
  8.                   -- by ahkai    SAAS(软件即服务) 离我们 ... 
  9.                   呵呵,在中国,我不看好这种模式,对个人也许有用,但在企业领域,恐怕很难推广。如楼 ...
  10.                   -- by zlxym    以无法为有法,以无限为有 ... 
  11.                   呵呵,楼主还是单纯技术人员的创办思路。缺少营销、商业气味!这道也不是什么坏事,但 ...
  12.                   -- by cljhyjs      评论排行榜    Warp framework - 一个相当有前途的Java轻 ...    《太阳照常升起》观后感    关于JavaEye网站未来发展的思考    从分布式系统的角度看REST    Java已经过时了吗?                            [什么是RSS?]           
  13.           声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。若作者同意转载,必须以超链接形式标明文章原始出处和作者。
  14.           © 2003-2008 JavaEye.com.   All rights reserved. 上海炯耐计算机软件有限公司 [ 沪ICP备05023328号 ]

这上面有的地方有很多空格,这一段就要去掉。当然可以再对段做分析,将一段中空格多的地方去掉。
好了经过整理,现在得到了质量稍好一点的文本了。我们进行分析分词。分词,我是在一个叫hightman的开发者的作品的基础上包装了一个ruby库,原文地址是http://www.hightman.cn/bbs/viewthread.php?tid=321.Ruby是一门很好的胶水语言,但是性能较差,因此对性能要求高的部分我选择用c封装ruby模块。
分好词了,我们再抽出一些实词,比如名词(联想集团),动词(上市,IPO,收购),其实主要思路是跟IT、商业有关的(q我们事先整理一张表,将这些词放进来),将无意义的词(很好,缓慢,深深地…)去掉,对频度,权值排个序,取出前20个,
记为主题词。
现在这个也做好了以后我们将文本、主题词入库。再对每一篇文本计算相似文章。这个,我开始是打算就将关键词和文章都存入数据库,然后按照文章之间主题词的重合度来算,但是后来发现文章数越多这个计算就越复杂,并且运算量随文章数的增长而增长,而且增长更快(指数的而不是线性的增长).
后来想了个办法,我正好也需要一个全文索引,于是利用这个全文检索来完成。全文检索当然不是自己做,现成的有不少系统。用一篇文章的关键词去搜索,搜索结果中的文章就是这篇文章的相似文章。
至于热点事件挖掘,现在还不知道如何去实现一个demo.可能首先要依赖分词引擎的新词发现比较准确吧。
搞定以后,有一个问题,我的抓取和分析模块都在我的台式机上完成,但是我需要把数据传输到远程主机上。这点到后面也就用了不到100行代码搞定了(我自己手工写的代码,在40行以内!).因为,一个rails2.0的组件叫activerecord,还有一个叫activeResource,而rails的scaffold可以帮我生成rest协议的相关代码。需要我手工写的代码是:

  1. for item in @items
  2.                     post=Post2s.new
  3.                     post.title=item.title
  4.                     post.md5=item.md5
  5.                     post.body=item.description
  6.                     post.rss_pub_date=item.pubDate
  7.                     post.service_id="blog"
  8.                     ....
  9.                     post.save
  10.             end

简单明了,谁都看得懂.这是一段运行在我的台式机上的代码,但是他保存的时候,却与远程的主机交互将数据保存在了服务器上,走的是HTTP通道,数据交换格式是HTML/XML.
Ruby 果然很适合用来替代很多难度不大但是需要大段废话的场合。
下一篇就写如何搞中文分词的ruby包装。


Tag:
相关文章


     
    Apr
    07
    Posted (xurenlu) in Ruby on 04月-7-2008

    经过好几个周末的准备,Ror 版的博客即将到来了
    要换掉Wordpress,其实没有什么理由。只是,我天生是小白鼠的命。rails升级到2.0后,实在忍不住,就自己做了一个博客。
    当然,wordpress也有不少不对我胃口的地方:

    1. 皮肤系统太复杂。虽然我推荐用php本身做模板引擎,但我不喜欢这种模板方式,对UI/UE工程师来说太难了。这次我自己照着mozilla addons社区的样子自己做了皮肤。以后自己给自己做皮肤。新的博客程序,很容易制做新皮肤。
    2. event based的插件方式很酷,可以说是插件成就了wordpress,但是,wordpress的代码太混乱了,结构化太差
    3. js基于prototype,而有些插件又是jquery的。现在我最拿手的是YUI,另外比较顺手的一个是mootools,mozilla和UWA都在用的一个js library.这次的程序,我也会混用几种引擎,但主要以mootools为主。
    4. 文件上传,管理部分不太符合我的胃口。我要一个像册,还要一个作品下载模块。新的程序要内置文件上传和管理部分
    5. wordpress用的人太多了,针对wordpress的spam程序太多了,防不胜防。但是现在的wordpress是我自己写的评论部分,spam少了很多.垃圾评论是新版博客程序一个重要考虑因素。如果可能,加入垃圾评论学习机制。
    6. 写的程序demo类的东西比较多,新程序要能有较好的支持。
    7. ….对,除了上面的,还有重的特性:支持RestAPI,包含一个Ruby写的客户端,这样可以在终端中用vim写博客,然后发布。

    嘿嘿。最最最重要的是,以后我的方向是前端工程师了….呼呼。。。不知PHP程序员能不能成为一个牛B设计师呢?


    Tag:
    相关文章


       
      Mar
      23
      Posted (xurenlu) in Ruby on 03月-23-2008

      1.ActionView的变化:
      模板文件默认扩展名从.rhtml改成了.html.erb
      新的规则是:[动作名.扩展名.渲染引擎],因此黙 认模板文件就是类似view.html.erb.当然view.rhtml也能正常工作.
      比如我希望用户访问/post/rss/1.atom时,调用builder来解析,我的模板文件应该是rss.xml.builder.这个builder很方便,创建Rss时非常爽。语法像这样:

      xml.instruct!
      xml.rss(”version”=>”2.0″,
      “xmlns:dc”=>”http://purl.org/dc/elements/1.1/”) do
      xml.channel do
      xml.title “renlu.xu ’s blog”
      xml.link(url_for(:action=>”start”,:only_path=>false))
      xml.description “My life My love”
      xml.language “zh_CN”
      xml.ttl 60

      for event in @posts do
      xml.item do
      xml.title(event.title)
      xml.description(event.body)
      xml.pubDate(event.created_at.to_s(:rfc822))
      xml.guid(event.id)
      xml.link(”http://…..#{event.id}”)
      end
      end
      end
      end

      2. 一些Helper改进了
      我能感觉到的是,在生成表单时,生成时,用form_tag能生成一个表单,这个表单默认带了一个隐藏的域。这个域的值是一个加密的串,用来验证当前表单提交的合法性。这一点很好。yahoo的产品体系中,也有类似的检查,叫crumb机制。存有不包含crumb的from表单提交时,程序是不能通过安全审查的。
      3 Router的改进。
      将用分号来区隔的方法去掉了。比如/post/view/1:edit这种就去掉了。统一成了斜线方式:/post/view/1/edit。
      经过我测试,rails的route好像存在一个很可耻的Bug…..有些地址死活不能被认出来…
      另外,route需要Sqlite3的支持。
      4 默认的数据库支持类型据说换成sqlite3了。render_text 被去掉了
      5… 不少Bug 仍然性格倔强地拒绝被修改….


      Tag:
      相关文章


         
        Oct
        06
        Posted (xurenlu) in Ruby, 未分类 on 10月-6-2007

        题目其实错了。

        ruby的确是个不错的语言,正如名字一般,像宝石一样。另一个语言也是,lua,名为月亮,也很棒。

        但是我用ruby来构建一个微型的抓取/索引/检索系统,分词,存储,检索都没什么问题,但是在抓取HTML页面解析时出了问题:因为我用了一个库,这个库又依赖于另一个库…. 最后输出时输出一大篇大篇的出错信息,我只好加上ruby spider.rb 2> /dev/null 才能看到我自己的调试信息。 试了一下,原来用begin rescue end 语句不太好用,仍然无法阻止错误信息的输出。

        刚刚又发现,用gem build rlucene.gemspec来打包时,又莫名奇妙地出错了.

        郁闷。ruby库的可靠性真不怎么样。


        Tag:
        相关文章


           
          Jul
          16
          Posted (xurenlu) in Ruby, 未分类 on 07月-16-2007

          前一阵偏离了方向,一直在努力地做分词的性能优化。
          后来发现,有时越优化性能反而越差,所以打算改改方向。
          于是挑了一个版本拿出来随便打了一个包,版本号定为0.13,就这 么发出来了。
          这一个月时间才出来了一个版本却还不让我自己满意。不过先放出来吧。
          马上学习一下Ferret,打算在下一个版本开始引入它的一些特性。现在的rlucene实际上还根本不能为检索提供任何实质用处….(我脸皮还真厚吧?)
          Rlucene地址:https://rubyforge.org/projects/rlucene/
          更新手记:
          2007.7.3
          1.加入了对网址,数字的预先处理,这类词能正确处理.
          2.autotag.gettags返回的词能自动去重了.
          2007.7.1 今天我改动不少:
          1.分词时引入jcode,效率提高不少.
          2.autotag和segserver改写了,减少重复的操作
          3.用Marshal保存词库数据,启动速度提高不少

          2007.6.24 example/demo edition 0.09 将公司的php的基础服务做完之后,忽然很 有成就感,原来以为会很难的东西竟然一周内全盘搞定,权限系统,Cron服务,多mysql server架构问题,all done,非常爽,于是加紧把这个project给改了一下.
          解决了一个Bug:就是在一段中文一段英文的情况下分词时,会丢失中文的最后 一个词.
          但是我认为还是不适合实用.
          to do: 下一步我将从互联网上抓到大约100,000条大文本,然后做分词检测,算出最常见词,在某些应用中会用到.
          2007.6.16 example/demo edition 这是我学完python之后做完分词demo后一边啃ruby 一边做出来的东东。
          可能不太好,只能给大家提供一种分词,索引,搜索的思路罢了。
          慢慢完善之后,在下一版争取加入异常处理之类的。
          这一版我甚至不知道如何加入注释,加”#”还是我猜出来的..
          完成后一直还在想为什么ruby没有异常处理,原来ruby其实是有的,只是我没有google 到相应文档而已。


          Tag:
          相关文章


             
            Jul
            12
            Posted (xurenlu) in Ruby, 未分类 on 07月-12-2007

            优化ruby版的分词,从44s每一千文本文件到了20多秒每一千文本文件后,再也优化不下去了。烦闷之极,发现这个现象:

            [st@localhost segment]$ ruby segment.rb
            time:24.292177
            [st@localhost segment]$ ruby segment.rb
            time:18.223328
            [st@localhost segment]$ ruby segment.rb
            time:17.331675
            [st@localhost segment]$ ruby segment.rb
            time:17.316683
            [st@localhost segment]$ ruby segment.rb
            time:17.275409

            太神了,我连打几次命令,它自已运行就越来越快了?


            Tag:
            相关文章


               
              Jul
              08
              Posted (xurenlu) in Ruby on 07月-8-2007

              昨天下午,myspace.cn罗川一行过来演讲。用手机抓拍了几张,打算放到空间上来。
              没想到的是,这个gd又不含jpg的支持。
              于是一郁闷,用ruby写了一个简单的像册。
              http://photo.162cm.com/
              不过目前服务器上仍缺Rmagick或是ImageMagick,所有的照片我只能是忽乱地放一些上去,等缩图用的imagemagick装上之后,就可以给大家秀秀我的照片了。我的电脑上都存了几个G的照片了。
              覃总真是个有洁癖的人,服务器上一点也不肯多装。而我就不含忽,一来就给他用上10%以上的CPU占用。

              Ruby On rails真是个好东西。
              这样一个能上传/生成缩略图/管理/检索的像册(带顺手加了一个thickbox特效),两个小时就搞定了。另外,为了简单,它还不是Mysql做的存储。为了方便迁移,我把图处信息都放在文本文件里面。
              听说RoR已经在JavaEye等一些较大的商业性网站上运行起来了,每天确认能支撑50W的Pageview 估计慢慢会火起来的。


              Tag:
              相关文章


                 
                Jun
                16
                Posted (xurenlu) in Ruby, 未分类 on 06月-16-2007

                中文分词一直是一个看起来似乎比较神秘的东西。记得java中的lucene好像自带了两个分词器。一个是按汉字分,就是一个字分成一个词。比如”我要到饭馆吃饭“,就被分成”我/要/到/饭/馆/吃/饭”.别一个是相邻的两个字分成一个词,分出来的结果是”我要/要到/到饭/饭馆/馆吃/吃饭”.然而这两种虽说在做搜索时建索引什么的操作时也是相当有用的,但是毕竟是一种权宜之计,咱不能一直停留在这个水平上。

                下面是来自Rlucene的一段示例代码,154行,利用sogou的词库搞定了中文分词。代码如下:

                #! /usr/bin/ruby
                require “socket”
                #通过网络得到分词结果
                def segChinese_net(line)
                @conn=TCPSocket.open(”localhost”,1099)
                @conn.write(line)
                line=@conn.read
                return line.split(” “)
                end
                @f= open(”dict/sogou.txt”)
                @datas=@f.read.split(”\n”)
                @f.close

                @f2=open(”dict/firstword.txt”)
                @firstwords=@f2.read.split(”\n”)
                @f2.close
                @maintable=Hash.new()
                @firstwords.each{|x|
                @maintable[x]=[x]
                }
                @datas.each{|x|
                @maintable[x[0].chr+x[1].chr+x[2].chr].push(x)
                }
                def segChinese(line)
                temp=0
                max=(line.length/3)
                words=[]
                while(temp
                pos=temp*3
                str1=line[pos].chr+line[pos+1].chr+line[pos+2].chr
                str12=str1
                str1234=str1
                if(temp<(max-1))
                str2=line[pos+3].chr+line[pos+4].chr+line[pos+5].chr
                str12=line[pos].chr+line[pos+1].chr+line[pos+2].chr+line[pos+3].chr+line[pos+4].chr+line[pos+5].chr
                end
                if(temp<(max-3))
                str1234=line[pos].chr+line[pos+1].chr+line[pos+2].chr+line[pos+3].chr+line[pos+4].chr+line[pos+5].chr+line[pos+6].chr+line[pos+7].chr+line[pos+8].chr+line[pos+9].chr+line[pos+10].chr+line[pos+11].chr
                end
                if(!@maintable[str1].nil?)
                if(!@maintable[str1].index(str1234).nil?)
                temp+=4
                words.push(str1234)
                else
                if(!@maintable[str1].index(str12).nil?)
                temp+=2
                words.push(str12)
                else
                words.push(str1)
                temp+=1
                end
                end
                else
                words.push(str1)
                temp+=1
                end
                end
                return words
                end
                #return an array of the segemention.
                #得到当前句子的分词结果.
                def segment(str)

                chars=Hash.new(0)
                chars["char"]=”~!@#$\%^&*()_+}{[]\\|\”‘:;/?><,. \t\n\b\a”
                chars["num"]=”0123456789″
                chars["alpha"]=”abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ”
                bytes=Hash.new(0)
                i=0
                buffer=”"
                #oldtype 表示上一个字符的种类:字符还是字母还是数字
                #newtype表示本字符的种类
                #type:1,表示字符,2表示数字,3表示字母,4表示属于汉字(多字节字符)
                #Buffer用来存储当未完成的一个词.
                #只有当当前字符类型与前一个字符类型不一致时才输出buffer,并清空buffer,改为当前字符值.
                #当与前一字符类型相同时,仅是把当前字符推入buffer(加到buffer的后面)
                #oldtype为4时,当输出一个buffer时,还需要对当前buffer进行中文分词
                oldtype=0
                newtype=0
                flag=0
                words=[]
                0.upto(str.length-1){|a|
                if(flag>0)
                flag=flag-1
                else
                x=str[a]
                if(!chars["char"].index(x.chr).nil?)
                newtype=1
                if(newtype==oldtype)
                buffer=buffer+x.chr
                else
                if(oldtype==4)
                words.concat(segChinese(buffer.strip))
                buffer=x.chr
                else
                words.push( buffer) if (buffer.strip!=”")
                buffer=x.chr
                end
                end
                oldtype=1
                end
                if(!chars["num"].index(x.chr).nil?)
                newtype=2
                if(newtype==oldtype)
                buffer=buffer+x.chr
                else
                if(oldtype==4)
                words.concat(segChinese(buffer.strip))
                buffer=x.chr
                else
                words.push(buffer) if (buffer.strip!=”")
                buffer=x.chr
                end
                end
                oldtype=2
                end
                if(!chars["alpha"].index(x.chr).nil?)
                newtype=3
                if(newtype==oldtype)
                buffer=buffer+x.chr
                else
                if(oldtype==4)
                words.concat(segChinese(buffer.strip))
                buffer=x.chr
                else
                words.push(buffer) if (buffer.strip!=”")
                buffer=x.chr
                end
                end
                oldtype=3
                end
                if(x>127)
                flag=+2
                newtype=4
                if(newtype==oldtype)
                buffer=buffer+str[a].chr+str[a+1].chr+str[a+2].chr
                else
                words.push(buffer) if(buffer.strip!=”")
                buffer=str[a].chr+str[a+1].chr+str[a+2].chr
                end
                oldtype=4
                end
                end
                }
                if(oldtype==4)
                words.concat(segChinese(buffer.strip))
                else
                words.push(buffer) if(buffer.strip!=”")
                end
                total=”"
                words.each{|x| total=total+x+” “}
                return total
                #puts total
                end

                ruby果然就是牛B极了。在学着用BCB折腾nsapi的时候 ,发现了asp,于是我觉得asp真是一个比较牛B的东西。接着发现了php,于是我扔掉了asp, 接着发现python比php有前途,现在,python还没摸透,又瞅 上ruby了。世界变化真是太快了,我快跟不上啦。

                不过要实用,可能还得做些调整。 一般来说,分词的词库得自己整,sogou这个示例可以,真起来肯定有问题。而且要实用,在结果准确度上还要下功能。


                Tag:一个 分成 饭馆 吃饭 两个 我要 中文 利用 下面 来自 
                相关文章