zoukankan      html  css  js  c++  java
  • 改写lucene的Analyzer,添加自己的中文分词系统的方法

    http://hi.baidu.com/chanajianxin/blog/item/9b36608bb7dfc013c8fc7a9c.html

    改写lucene的Analyzer,添加自己的中文分词系统的方法(原创)
    2007-04-30 16:16

    /**
    *作者:夺天策      百度空间名:刹那剑欣
    *转载请说明出处!   
    */

        这几天完成了我的中文分词算法,就着手把它加入到lucene中去,google,baidu一下,倒是有一些人写的中文分词,和加入的方法,但是那些都 是符合他们自己写的分词算法的添加方法,没有讲到lucene的添加接口,没有将原理,于是就自己研究了下咯,看了下lucene的源代码,总结出方法, 希望对现在还不知道的朋友会有帮助!!

    源代码中主要分词器都在analysis 这个包中,在contrib中还有一些第三方的分词器,有一个中文分词器ChineseAnalyzer.java,但是他只是实现了二分(没两个汉字算作一个Token或者Term)方法的分词,对实际应用显然不能满足

    所有的Analyzer都有一个抽象的父类Analyzer
    lucene源代码:public abstract class Analyzer
    每个子类的Analyzer都继承与这个类,并且实现这个类的tokenStream方法
    lucene源代码:public abstract TokenStream tokenStream(String fieldName, Reader reader);
    这个方法返回的是一个TokenStream实例(其实不是TokenStream实例,因为下面会开到TokenStream其实是一个抽象类,这里应该说是返回实现这个抽象类的实例)。要了解这个类,必须去看看这个类的源代码
    TokenStream类:
    public abstract class TokenStream {
         /** Returns the next token in the stream, or null at EOS. */
         public abstract Token next() throws IOException;

         /** Releases resources associated with this stream. */
         public void close() throws IOException {}
    }

    我们可以看到,这个类中有两个方法,主要的是一个next()方法,这个方法没调用一次反回一个Token实例,要想了解Token类,必须再看lucene的源代码咯

    由于源代码有点长,贴出最核心的几个变量和方法
    String termText;         // the text of the term
         int startOffset;         // start in source text
         int endOffset;         // end in source text
         String type = "word";         // lexical type
         private int positionIncrement = 1;
    public Token(String text, int start, int end) {
           termText = text;
           startOffset = start;
           endOffset = end;
         }
    public Token(String text, int start, int end, String typ) {
           termText = text;
           startOffset = start;
           endOffset = end;
           type = typ;
         }
    。。。。。。

    我们看到一个Token是有一个TermText,startOffset,endOffset,type,positionIncrement.....等组成,有两个构造函数。大体的结构就是这样了。下面我们看看个lucene现成的Analyzer的例子:SimpleAnalyzer.java


    public final class SimpleAnalyzer extends Analyzer {
         public TokenStream tokenStream(String fieldName, Reader reader) {
           return new LowerCaseTokenizer(reader);
         }
    }

    我们看到他继承了Analyzer并且重写了方法tokenStream,返回一个TokenStream,我们知道TokenStream是一个 抽象的类,LowerCaseTokenizer也是继承了这个抽象类,所以lucene可以这样返回一个LowerCaseTokenizer当作是 TokenStream,这里我们不再继续通过LowerCaseTokenizer分析下去了,因为LowerCaseTokenizer又是继承与 TokenFilter,而TokenFilter又是继承 TokenStream,有点乱。呵呵,我们这里只需要了解,新建的Analyzer需要继承Analyzer这个类,并且实现一个返回 TokenStream的tokenStream方法,而通过上面的分析,我们知道,我们只需要写一个类继承与TokenStream,并且实现其中 next()方法,比如我们起名为:KinggouTokenStream,这个类源代码如下:

    public class KinggouTokenStream extends TokenStream{

    public KinggouTokenStream(Reader reader){....//把reader对象变成String,并且在next方法中每次将一个词组封装为Token类型,然后返回!}

    /**这个方法很关键,你每次next都必须返回一个 Token实例(在上面我有谈到),这里你可以在next方法中,实例化一个Token,并且把其中的TermText赋值为 分词出来的词组,然后startOffset和endOffset其实是这个次在整个token流中的首位置和尾位置,你可以通过分词得到的词组的 length去加基数去实现。
    **/
    public Token next() throws IOException{...............}

    }

    kinggouTokenStream 完成了,接下类写真正的Analyzer类,我们起名为KinggouAnalyzer,源代码如下:

    public class kinggouAnalyzer extends Analyzer {

    public TokenStream tokenStream(String filename, Reader reader) {
          //你需要在kinggouTokenStream中把这个reader对象读取为String,并且分词,然后为next方法定 义每次返回一个Token对象
             return new kinggouTokenStream(reader)
    }
    }

    以上类都是便于理解写的,不一定保证能编译通过,只是写了主要的方法!
    附上kinggou的写法:

    --------------下面的是KinggouTokenStream,具体项目中我用SegmentOutInterface代替了-----------------

    /**
    * the interface of Segment to outside
    * extend org.apache.lucene.analysis.TokenStream
    * method: next()     return Token
    * 分词对外的接口,继承 lucene的TokenStream
    */

    package com.kinggou.engine.segment;
    import java.io.IOException;
    import java.util.StringTokenizer;

    import org.apache.lucene.analysis.Token;
    import org.apache.lucene.analysis.TokenStream;

    //SegmentOutInterface相当与上面的kinggouTokenStream

    public class SegmentOutInterface extends TokenStream {
    int start=0;
    int end=0;
    String list;
    StringTokenizer st;
    public SegmentOutInterface(String str){
    //这里是分词的实现,分词实现有我写的一个具体的包,这里不写出
         list=WordSegment.getInstance().Segment(str, " ");;
         st=new StringTokenizer(list);
    }
    String temp;
    Token tk;

    /**
         * 实现的核心方法
         * */
    @Override
    public Token next() throws IOException {
       if(st.hasMoreTokens()){
        temp=st.nextToken();
        end=start+temp.length();
        tk=new Token(temp,start,end);
        start=end+1;
        //end=end+temp.length();
       }else{
        tk=null;
       }
       return tk;
    }
    }

    ---------------------------------下面的是kinggouAnalyzer----------------------

    package com.kinggou.engine.index;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.Reader;
    import org.apache.lucene.analysis.Analyzer;
    import org.apache.lucene.analysis.TokenStream;
    import com.kinggou.engine.segment.SegmentOutInterface;

    public class kinggouAnalyzer extends Analyzer {

    /**
         * 改写的lucene自己的分析器
         * */
    @Override
    public TokenStream tokenStream(String filename, Reader reader) {
         StringBuffer str=new StringBuffer();
         BufferedReader br=new BufferedReader(reader);
         String temp="";
         try {
          temp = br.readLine();
         } catch (IOException e) {
          e.printStackTrace();
         }
         while(temp!=null){
          str.append(temp);
          try {
           temp=br.readLine();
          } catch (IOException e) {
           e.printStackTrace();
          }
         }
         return new SegmentOutInterface(str.toString());
    }

    }

    ok,完毕。。。。



  • 相关阅读:
    CVPR2020:三维实例分割与目标检测
    CVPR2020:视觉导航的神经拓扑SLAM
    使用现代C++如何避免bugs(下)
    使用现代C++如何避免bugs(上)
    蓝牙mesh网络技术的亮点
    电路功能和优点
    ARM的突破:超级计算机和Mac
    所有处理都走向AI
    Wide-Bandgap宽禁带(WBG)器件(如GaN和SiC)市场将何去何从?
    功率半导体碳化硅(SiC)技术
  • 原文地址:https://www.cnblogs.com/lexus/p/2196814.html
Copyright © 2011-2022 走看看