zoukankan      html  css  js  c++  java
  • 打造自己的中文分词器之如何让Lucene认识自己的分词器

    Lucene允许分词器的扩充,或换句话说也就是允许你自己编写的分词器应用到Lucene中,那么Lucene是如何做到这点的呢?如果让我们来自己设计,我们会如何做呢?下面将以Lucene自带的标准分词器StandardAnalyzer来予以说明
    首先看一下StandardAnalyzer的代码,为了显示简洁,以及突出重点,将不显示StandardAnalyzer的所有代码,先来看:
    1public class StandardAnalyzer extends Analyzer {
    2 public TokenStream tokenStream(String fieldName, Reader reader){
    3 TokenStream result = new StandardTokenizer(reader);
    4 result = new StandardFilter(result);
    5 result = new LowerCaseFilter(result);
    6 result = new StopFilter(result, stopSet);
    7 return result;
    8 }
    9} 可以看到StandardAnalyzer继承了一个Analyzer类,这时你如果再查看下Lucene自带的其他分词器,你会发现所有的分词器,比如KeywordAnalyzer,SimpleAnalyzer等等都继承了这个类,那么由此便可几乎可以肯定这个类便是Lucene提供外来分词器融入Lucene的一个准入证,然后我们看看Analyzer究竟是个什么东西?如下:
    1public abstract class Analyzer {
    2 public abstract TokenStream tokenStream(String fieldName, Reader reader);
    3 public int getPositionIncrementGap(String fieldName){
    4 return 0;
    5 }
    6} 原来是个抽象类!而抽象类主要就是干这活的,那就是提供一个通用的接口让别人去继承,而自己却懒得去干具体的活,这更证明了这点,要想自己写的分词器融入到Lucene中,必须继承这个类!接下来再看它的方法
    public abstract TokenStream tokenStream(String fieldName, Reader reader);里的TokenStream字面意思理解为分词流,什么意思呢?按我自己的理解,流在java里是与内存联系在一起的,分词流的意思就是分词在内存中以流的形式存在,或者说如果我们要得到分词对象(Token),就要通过TokenStream这个东西来得到,这个解释听上去可能有些不大好理解,在这里,我尽可能地以自己的理解来解释,在后面中我也会拿出实际的代码来予以说明,在Lucene对TokenStream的英文解释为A TokenStream enumerates the sequence of tokens, either from fields of a document or from query text.如果有看得懂的朋友就不用看我的解释了,看这段英文就好了.
    public abstract TokenStream tokenStream(String fieldName, Reader reader);这句中的第一个参数表示一个字段名,也就是你建索引的时候对应的字段名,比如:Field f = new Field("title","hello",Field.Store.YES, Field.Index.TOKENIZED);这句中的"title";而reader是java.io.Reader对象,顺便提一下,java.io.Reader也是一个抽象类,是用来读取字符流的,其用法大致为:
    1String s = "hello";
    2reader = new StringReader(s); //StringReader继承自Reader 那么这一整句表示的就是:返回一个TokenStream对象,而这个TokenStream对象是由一个字段和这个字段对应的要分词的文本所转换成的Reader对象决定的,这个解释同样听上去也比较拗口,不过之后我也会尽量用代码来予以说明的。关于Analyzer类中的public int getPositionIncrementGap(String fieldName),这个在分词器的编写过程中没有用得上,所以不是很重要,不过用已有的中文解释为:在建立索引时,处理重复词条的位移增量问题,至于英文注释很长,这里就不列出了,有源码的朋友可以自己去看吧。
    好了,分析完Analyzer,我们再回到StandardAnalyzer来瞧一瞧吧,在StandardAnalyzer中,通过上面的分析,我们已经知道了public TokenStream tokenStream(String fieldName, Reader reader)是返回一个TokenStream对象,而这个TokenStream对象是由一个字段和这个字段对应的要分词的文本所转换成的Reader对象决定的,但是我们再看看方法体,发现还有好几行代码,下面分别予以简单说明:
    1TokenStream result = new StandardTokenizer(reader);//表示用StandardTokenizer对这个要分词的reader进行处理(不知道为啥想起了《这个杀手不太冷》中的那个主人公回答那个小姑娘问他是干啥时候的回答:我是清道夫cleaner),然后返回一个TokenStream对象
    2result = new StandardFilter(result);//表示对上面由"清道夫"进行清理后的TokenStream对象进行过滤(Filter)
    3result = new LowerCaseFilter(result);//表示对上面由"StandardFilter"过滤后的TokenStream对象再进行次过滤(跟广告中所说的纯净水经过多少次过滤后的道理其实一样的)
    4result = new StopFilter(result, stopSet);//接下来再进行次过滤,此次过滤后,达到了国家规定标准,此纯净水就可以喝了
    5return result;//XXX牌纯净水可以正式上市出售了! 从上面的分析中可以得出这样一个结论,在一个分词器中:
    1.有进行分词的Tokenizer(StandardTokenizer)
    2.有进行过滤的Filter(比如LowerCaseFilter等)
    所以总的结论为:一个分词器(Analyzer)包括一个Tokenizer和若干个Filter(不同的分词器所有的Filter个数不一定相同,就如同不同的纯净水品牌,过滤的次数不同一样)
    现在问题就回到了此文的最初了,如何让Lucene认得自己编写的分词器并让分词器融入到Lucene温暖的大家庭中呢?很显然,我们要按照Lucene提供的准入规则来办,因此,如果你想写一个XXXAnalyzer自定义的分词器,那么你得:
    1.继承一下Analyzer,让Lucene知道我是很诚心地想融入到这个温暖大家庭中的,public class XXXAnalyzer extends Analyzer
    2.然后加入之后要干活呀,不能终日游手好闲,所以得努力干活呀:于是public TokenStream tokenStream(String fieldName, Reader reader),在这个方法中定义了你干活的工具:锄头Tokenizer(锄禾日当午,汗滴禾下土)和镰刀Filter(我割我割我割割割)
    3.然后告诉Lucene,我干完了一件活(return result;)
    Ok,就是这样了!让Lucene认识自己的分词器很简单吧?Lucene刚看上去的时候很严肃,让人摸不着脾气,其实熟悉后会发现这“人”挺不错的!
    附:
    1.细心的朋友一定会发现在StandardAnalyzer中还有好几段代码,是关于StopFilter的,由于这篇博文主要讲的是剖析StandardAnalyzer从而得知如何让Lucene认识自己的分词器,而StopFilter在其中显得并非是必须的,所以先暂时略过,留待以后有空的时候再补上。
    2.关于XXXAnalyzer的中文命名,我这里是统一将XXXAnalyzer命名为分词器,而按照英文字面意思理解应为分析器,有的书上也是翻译为分析器,而我觉得我们更直接想到的是对中文进行分词,所以就直接命名为了分词器,实际上,Tokenizer才是分词器,也是构成XXXAnalyzer的一部分,但XXXAnalyzer的主要工作其实就是Tokenizer干的活,特此说明。
    如若转载,请注明作者为:bbmonkey62 出处:http://www.blogjava.net/bbmonkey62(或文章地址) 谢谢合作
    本文来自: ★编程爱好者博文★ http://www.08s.cn 详细出处参考:http://z20.5mso.com/html/JAVAboke/200811/dazaozijidezhongwenfenciqizhiruherangLucenerenshizijidefenciqi-si-_1136.html

  • 相关阅读:
    MVC3中输出Html标签的方法
    Server.MapPath 出现未将对象引用设置到对象的实例
    谈谈网站静态化
    WCF 服务应用程序与 服务库之间的区别
    插入中国所有省和市的SQL语句--以后用
    KiCad 元件值 F4NNIU 规范 (2020-04-30)[31.98%]
    FastAdmin 安装后点登录没有反应怎么办?
    笔记:读英国老太太的复仇计划 (2019-10-15)
    KiCad 工程用 Git 管理需要忽略哪些文件?
    关于 SSD 的接口和相关名词(2019-09-10)
  • 原文地址:https://www.cnblogs.com/liaomin416100569/p/9331822.html
Copyright © 2011-2022 走看看