`
everlook
  • 浏览: 111610 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

庖丁解牛分词分析

    博客分类:
  • java
阅读更多
    庖丁系统是个完全基于lucene的中文分词系统,因而它就是重新了一个analyer,叫做PaodingAnalyzer,这个analyer的核心任务就是生成一个可以切词的TokenStream这些都是lucene的结构设计,如果要和lucene一起使用就要这么写。
    庖丁系统中的TokenStream就是PaodingTokenizer,它提供了我们用于分词的核心方法
next,它每次调用的时候返回切好的一个词。它采用了一个迭代器来进行的缓存,因而它不
是每次调用都会去拿出一堆刀来进行切词,它一般会一次切一堆然后将它保存下来,然后等
取完了再切第二次。
    切词的时候它是直接调用了knifebox的dissect方法来进行切词的
    knifebox是个刀盒子,它有一个刀的数组,它的dissect方法会调用刀的assignable方法
来决定是否可以用这个刀来切,如果用一个刀切了,但是没有切出任何词,即刀返回的最后切词的位置与开始位置一样则换下把刀切,如果切出了词,那么就直接返回最后切的位置,再不换刀切了,同时等待下一次切词。
    在这个系统中还有paoding和SmartKnifeBox两个子类他们都是继承knifebox,但是它们只是做了一些简单的检查工作,主要工作还是由这个基类来完成。


    分词策略的问题,我们在代码中看见庖丁系统的分词,它在分词的时候尽量将多的词语分出来,但是在PaodingAnalyzer发现它是有两种mode,一种是MOST_WORDS_MODE,一种是MAX_WORD_LENGTH_MODE,从字面上就可以看出它们的策略,前者是表示尽可能多的分词,即“华中科技大学”直接分为“华中/华中科技/华中科技大学/科技/大学/”,在CJKKnife中
当它遇到“华中”的时候就会开始collect,然后它将移动结尾,在分出“华中科技”和“华中科技大学”,这样“华”开头的就切完了,然后它将跳出小循环,进入下一轮大循环,移动开头位置,即“中”字,继续采用这个策略来切词,这样可以分出像上面那么多的词来,而这种方式用在索引的时候最好,可以保证索引中有尽可能多的关键词,这样找到的机会就大些。如果采用后一种mode,它将直接将上面分出的“华中/华中科技/华中科技大学/科技/大学/”只将最长的一个collect了,而前者会将它们全部collect。


    前一节简单的提到了分词时候的两种策略,这两种策略的实现实际上是采用使用不同
的collect来实现的,MostWordsTokenCollector对应于最多词策略,MaxWordLengthTokenCollector对应于最长词的策略。在最长词策略中,它是采用将前词分解的词先不要记录下来(保存在list中)而是将它作为候选,如果后面的词与它有一样的开头并且比它长,就替换它,如果和它有一样头的所有词都没有它长则将它记录下来(加入List中)。
   至于这个mode策略的选择,它是在PaodingAnalyzerBean中进行的,它在PaodingAnalyzer的init函数中调用了父类PaodingAnalyzerBean中的setmode方法设置mode,同时它产生了一个相应的classtype,最后根据这个classtype来通过反射生成一个collect传入PaodingTokenizer,供它使用。


==================================================================================


CJK刀

   CJK刀是庖丁解牛的主要的一个切词的刀,它的效率决定了整个中文分词系统的好坏。
   CJK刀同样会先调用assignable函数来判断一下当前的字符是否适合使用此刀,这个函数是所有刀所必须调用的它是庖丁系统中重要的一部分,它通常在发现当前一个字符时候使用此刀的时候会使用一个循环一次记录下所有适合的字符在Beef中的启始位置,以便一次用这个刀来切分这一段字符串。
   接着它就要开始正式的处理字符串。由于中文分词的是以词典为中心,因而它会不断的截取词语来在词典中进行比较。首先它将确定截取词语的开始位置和结束位置,得到这个词语后,它将直接放入词库中进行比较,如果在词库中的话,它将collect,并将孤立词的开始位置和当前截取词的开始位置之间的部分作为孤立词进行分解。同时它将继续移动结束位置,也就是说将词的开始部分不动,延长词语的长度,如“华中科技大学”,发现了"华中"这个词后,它将继续找“华中科”这个词,这个词显然不在词库中,但它却是一个词的开头,因而它不能确定为孤立字符串,如果发现它不是一个词的前缀,那么就将孤立字符串的开始位置和当前词语的开始位置设置为确定的词典词语的结束位置。但当它发现孤立字符串的开始位置为不是-1,也就是说前面几个字符都是孤立的,而且当前字符也是孤立的,则不要移动孤立字符串的开始位置,只移动当前词语的开始位置。
   如果延长的词语仍然是一个词语则将它collect,同时继续移动词语的结束位置。
   如果确定开始切分孤立字符串则将对孤立字符串进行二分的切分,所谓二分的切分,基本是二个字一切,"XY"切为"XY","X"切为"X","WXYZ"切为
"WX/XY/YZ","XYZ"切为"XY/YZ"。


简单来来说就是:
   1.在切词的时候词库词语优先切词。
   2.不在词典中的词语二分切词
   3.找到词典词语的时候贪婪的切词,就是说找到一个词后,继续往下找,找到以这个字开头的所有词为止。


ps:把别人文章抄了一遍,便于以后查看
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics