Lucene分词实现—Analyzer、TokenStream(Token、Tokenizer、Tokenfilter)

Lucene分词实现—Analyzer、TokenStream(Token、Tokenizer、Tokenfilter)一 分清概念:  1  TokenStream是用来走访Token的iterator(迭代器),       Tokenizer继承自TokenStream,其输入为Reader。       TokenFilter继承自TokenStream,其作用是用来完成对TokenStream的过滤操作,譬如 去StopWords,将Token变为小

大家好,又见面了,我是你们的朋友全栈君。

一  分清概念:

   1   TokenStream是用来走访Token的iterator(迭代器) ,

              Tokenizer继承自TokenStream,其输入为Reader 。

             TokenFilter继承自TokenStream,其作用是用来完成对TokenStream的过滤操作,譬如 去StopWords,将Token变为小写等。   

                 TokenStream:分词流,即将对象分词后所得的Token在内存中以流的方式存在,也说是说如果在取得Token必须从TokenStream中获取,而分词对象可以是文档文本,也可以是查询文本。

    2      Token:如果一个字段被token化,这表示它经过了一个可将内容转化为tokens串的分析程序。 Token是建立索引的基本单位,表示每个被编入索引的字符。 在token化的过程中,分析程序会在使用任何转换逻辑(例如去掉 “a” 或 “the” 这类停用词,执行词干搜寻,将无大小写区分的所有文字转换成小写等)的同时,抽取应被编入索引的文本内容。由于和字段相关的内容减少到只剩核心元素,因此,索引作为与某个字段相关的文字内容,它的规模也被缩小了。只有被token化的字段也将被编入索引的情况下才有意义。

    3   Analyzer就是一个TokenStream工厂 ,如下为其源码:

     public abstract class Analyzer { 
          public TokenStream tokenStream(String fieldName, Reader reader){

                        return tokenStream(reader);
         }
        public   TokenStream tokenStream(Reader reader){

                        return tokenStream(null, reader);
         }
        }

二    具体细节

1.1  分词流程

在Lucene3.0中,对分词主要依靠Analyzer类解析实现。Analyzer内部主要通过TokenStream类实现。Tonkenizer类、TokenFilter类是TokenStream的两个子类。Tokenizer处理单个字符组成的字符流,读取Reader对象中的数据,处理后转换成词汇单元。TokneFilter完成文本过滤器的功能,但在使用过程中必须注意不同的过滤器的使用的顺序。

Lucene分词实现---Analyzer、TokenStream(Token、Tokenizer、Tokenfilter)

1.2  分词扩展具体流程


1.2.1  Analyzer类分析


(1)所有的分词器都需要继承于Analyzer抽象类,它定义了tokenStream抽象方法。

   

            public abstract class Analyzer {

                    public abstract TokenStream tokenStream(String fieldName, Reader reader);
                  public TokenStream reusableTokenStream(String fieldName, Reader reader){}
    }

         该抽象类规定了Analyzer需要实现的一些方法。

(2)public abstract TokenStream tokenStream(String fieldName, Reader reader);

            

              该方法需要自定义的分词器去实现,并返回TokenStream,即将对象以Reader的方式输入分词为fieldName字段。


               TokenStream:分词流,即将对象分词后所得的Token在内存中以流的方式存在,也说是说如果在取得Token必须从TokenStream中获取,而分词对象可以是文档文本,也可以是查询文本。

              fieldName——字段名,也就是你建索引的时候对应的字段名,比如:Field f = new Field(“title”,”hello”,Field.Store.YES, Field.Index.TOKENIZED);这句中的”title”;

               reader——java.io.Reader对象;

(3)public TokenStream reusableTokenStream(String fieldName, Reader reader)。

                 设置为可复用TokenStream,将同一线程中前面时间的TokenStream设置为可复用。那些无必要同一时刻使用多个TokenStream的调用者使用这个方法,可以提升性能。

(4)接着,在tokenStream()方法实现中使用Tonkenizer和TokenFilter,例如StandardAnalyzer类中的tokenStream实现:

           //表示用StandardTokenizer对这个要分词的reader进行处理,然后返回一个TokenStream对象

           TokenStream result = new StandardTokenizer(reader);

                
          result = new StandardFilter(result);//表示对生成的TokenStream对象进行标准过滤(Filter)

           result = new LowerCaseFilter(result);//表示对上面由”StandardFilter”过滤后的TokenStream对象再进行次过滤,转化为小写

             result = new StopFilter(result, stopSet);//接下来再进行次过滤,去掉停止词

(5)  return result;//得到最终结果


      由此可以看出,主要的分词环节是Tokenizer类执行,而Filter负责数据的预处理和分词后处理且数量不限。


1.2.2  TokenStream类分析


TokenStream是一个抽象类,枚举词序列,要么是从一个文档的域得来,要么是从一个查询文本中得到。主要任务有:

    (1)获取下一Token;

     (2)重设流(可选);

     (3)关闭流,释放资源;

 

      public Token next();//取得词序列中的下一个词

      public Token next(final Token reusableToken);//输入可复用的Token,作为初始参数,可以返回一个新的Token

      public void reset();

     public void close();

        在Lucene3以后,next方法改为了incrementToken,并增加了end方法。

            public abstract boolean incrementToken() throws IOException;

            public void end() throws IOException;

 

 

1.2.3  Tokenizer类分析

                      Tokenizer类是继承于TokenStream的一个抽象类,是一个输入为Reader的TokenStream。其职责是:

 (1)接收输入流并根据输入流进行词切分。因此,该类是定制分词器的核心之一。

              publicabstractclass Tokenizer extends TokenStream {

                     protected Reader input;//增加了输入流Reader

                    protected Tokenizer() {}

                  protected Tokenizer(Reader input) {

                  this.input = input;

              }

                   publicvoid close() throws IOException {

                  input.close();

  }

 

  /**设置input到一个新的Reader*/

             publicvoid reset(Reader input) throws IOException {

                 this.input = input;

                }

    }

在Tokenizer类中,核心的方法是next方法,以CharTokenizer为例。

 publicfinal Token next(final Token reusableToken) throws IOException {

    assert reusableToken != null;

    reusableToken.clear();

    int length = 0;

    int start = bufferIndex;//起始位置

    char[] buffer = reusableToken.termBuffer();

    while (true) {

      if (bufferIndex >= dataLen) {//如果缓冲取大于数据长度,再读取到缓冲区

        offset += dataLen;

        dataLen = input.read(ioBuffer);

        if (dataLen == -1) {

          if (length > 0)

            break;

          else

            returnnull;

        }

         = 0;

      }

      finalchar c = ioBuffer[bufferIndex++];//无论如何都取一个字符

      if (isTokenChar(c)) {// if it’s a token char

        if (length == 0)                               // start of token

          start = offset + bufferIndex – 1;

        elseif (length == buffer.length)

          buffer = reusableToken.resizeTermBuffer(1+length);

        buffer[length++] = normalize(c); // buffer it, normalized

        if (length == MAX_WORD_LEN) // buffer overflow!

          break;

      } elseif (length > 0) // at non-Letter w/ chars

        break;                  // return ’em

    }

    reusableToken.setTermLength(length);

    reusableToken.setStartOffset(start);

    reusableToken.setEndOffset(start+length);

    return reusableToken;

  }

1.2.4 TokenFilter类分析

TokenFilter类继承于TokenStream,其输入是另一个TokenStream,主要职责是对TokenStream进行过滤,例如去掉一些索引词、替代同义索引词等操作。

 

1.2.5  Token类分析

(1)Token属性

lucene里定义了几种基本属性:

1)TermAttribute:表示token的字符串信息。比如”I’m”;

2)TypeAttribute:表示token词典类别信息,默认为“Word”,比如I’m就属于<APOSTROPHE>,有撇号的类型;

3)OffsetAttribute:表示token的首字母和尾字母在原文本中的位置。比如I’m的位置信息就是(0,3),需要注意的是startOffset与endOffset的差值并不一定就是termText.length(),因为可能term已经用stemmer或者其他过滤器处理过;

4)PositionIncrementAttribute:这个有点特殊,它表示tokenStream中的当前token与前一个token在实际的原文本中相隔的词语数量,用于短语查询。比如: 在tokenStream中[2:a]的前一个token是[1:I’m ],它们在原文本中相隔的词语数是1,则token=”a”的PositionIncrementAttribute值为1;

5)PayloadAttribute,payload即负载量意思,是每个term出现一次则存储一次的元数据,它存储于特定term的posting list内部。

6)FlagsAttribute,用于在Tokenizer链之前传递标记(因为前面一个操作可能会影响后面的操作)。

那么这个属性有什么用呢,用处很大的。加入我们想搜索一个短语student apples(假如有这个短语)。很显然,用户是要搜索出student apples紧挨着出现的文档。这个时候我们找到了某一篇文档(比如上面例子的字符串)都含有student apples。但是由于apples的PositionIncrementAttribute值是5,说明肯定没有紧挨着。

(2)核心方法

前面几个属性都作为其成员变量。

l  set、get方法

l  hashCode方法

(为什么要HASH?便于另一种方式去映射,常用的HASH算法有哪些?)

其典型的hash代码是code = code * 31 + startOffset,

l  copyTo方法

复制到另一个AttributeImpl中。

l  reflectWith方法

属性反射,从Token对象中解析得出属性。

参考:http://blog.csdn.net/jiejiuxunhuan/article/details/8534783

参考:http://ybzshizds.iteye.com/blog/562794

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/163087.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • eclipse 导入父子工程_eclipse 导入maven 父子项目

    eclipse 导入父子工程_eclipse 导入maven 父子项目你先要确认svn上是否是maven项目,否则要自己重新建一个maven项目然后直接引入目录了。如果确认是maven项目,那么有个两个方案。案一:先用任何client软件将svn下载。然后在eclipse选择import,然后当作existmavenproject导入。案二:在project中有checkoutmavenfromscm。scm就是指版本控制软件。不过不同版本控制的sc…

  • xman的思维导图快捷键_macz技巧分享:思维导图XMind快捷键汇总「建议收藏」

    xman的思维导图快捷键_macz技巧分享:思维导图XMind快捷键汇总「建议收藏」在思维导图XMind中,快捷键是可以大大提高绘图效率的存在。掌握常用的快捷键组合,就可以在键盘上运指如飞,快速地进行思维导图的绘制。还在等什么?感兴趣的朋友,下面就和小编一起来看看吧!在XMind:ZEN中,主要的快捷键类型有四种,分别是:文件(File)、插入(Insert)、编辑(Edit)和查看(View)。一、文件文件快捷键,指的是对当前文件整体的一个操作,常见的功能有…

  • 卸载Office 2007 Beta2后,Outlook 2003无法启动的解决方法

    卸载Office 2007 Beta2后,Outlook 2003无法启动的解决方法

  • Docker 常用命令!还有谁不会?[通俗易懂]

    Docker 常用命令!还有谁不会?

  • linux常用命令菜鸟教程_初学者化妆必备用品清单

    linux常用命令菜鸟教程_初学者化妆必备用品清单一.学习Linux终端命令的原因1.Linux刚面世时并没有图形界面,所有的操作全靠命令完成,如磁盘操作、文件存取、目录操作、进程管理、文件权限设定等2.在职场中,大量的服务器维护工作都是在远程通过SSH客户端来完成的,并没有图形界面,所有的维护工作都需要通过命令来完成在职场中,作为后端程序员,必须要或多或少的掌握一些Linux常用的终端命令。3.Linux发行版本的命令大概有200多个,但是常用的命令只有10多个而已二.linux常用指令ls命令…

  • javaweb注册登录案例(thinkphp注册登录源码)

    一、Servlet+JSP+JavaBean开发模式(MVC)介绍  Servlet+JSP+JavaBean模式(MVC)适合开发复杂的web应用,在这种模式下,servlet负责处理用户请求,jsp负责数据显示,javabean负责封装数据。Servlet+JSP+JavaBean模式程序各个模块之间层次清晰,web开发推荐采用此种模式。  这里以一个最常用的用户登录注册程序来讲解Servl…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号