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

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

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

(0)
上一篇 2022年7月22日 下午2:46
下一篇 2022年7月22日 下午2:46


相关推荐

  • springmvc接收字符串转list

    springmvc接收字符串转list多次试了下传入数组或者listjson格式感觉还是有问题。后面用最傻的方法先把参数设置成String类型传入到后台再做转换 publicObjectsaveScenceCheckDraw(CheckDrawingscheckDrawings,StringdrawingImgList){      GsonBuilderbuilder=newGsonBuilder();  …

    2022年5月14日
    71
  • 【游戏开发指路】Unity学习路线,三万字大纲(面试题大纲 | 知识图谱 | Unity游戏开发工程师)

    【游戏开发指路】Unity学习路线,三万字大纲(面试题大纲 | 知识图谱 | Unity游戏开发工程师)【游戏开发指路】Unity学习路线,三万字大纲(面试题大纲|知识图谱|Unity游戏开发工程师)

    2022年6月16日
    25
  • 搞不定Serverless?让你秒懂掌握Profiling让一份程序优雅自适应

    搞不定Serverless?让你秒懂掌握Profiling让一份程序优雅自适应学委好久没有更新 NodeJS 专栏 还以为 NodeJS 冷门 没想到最近看到几个读者留言问怎么优雅的管理多环境的配置 太忙了 写篇短文简单展示一下原理 正好基于前篇 NodeJS 后端开发 07MySQL 数据库连接池开发生产应用 简单尝试了 mysql 库来连接数据库 本篇尝试一个更加优雅的方式 通过环境变量来控制程序动态加载不同的配置 这个搞 Java 的同学最清楚 比如我们开发 springboot 应用的时候会放置多个 application yml 然后部署的时候通过环境变量来选择配置 这个用 Node

    2025年8月21日
    4
  • 时间复杂度是什么_时间复杂度的表示方法

    时间复杂度是什么_时间复杂度的表示方法-宝宝为啥听不懂他们在讨论的时间复杂度0.0-我怎么知道这个算法运行得比那个算法快0.0-我究竟会不会超时0.0-我为什么还会超时0.0-时间复杂度怎么算0.0在别人还不会求时间复杂度的时候而你会了是不是很酷在别人都会求时间复杂度的时候而你不会是不是很尴尬千里之行始于足下希望这篇文章能祝你一臂之力=w= 此篇详解,希望能帮助各位稍微解决一下不解=w=…

    2025年6月6日
    5
  • Visio2013 Professional专业版密钥

    Visio2013 Professional专业版密钥Visio2013密钥专业版:VisioProfessional2013KEYC2FG9-N6J68-H8BTJ-BW3QX-RM3B32NYF6-QG2CY-9F8XC-GWMBW-29VV8FJ2N7-W8TXC-JB8KB-DCQ7Q-7T7V3VXX6C-DN3HQ-3CRXG-RF4KT-YG7V3B3C7Q-D6NH2-2VRFW-HHWDG-FVQB6转载自:https://blog.csdn.net/alittleyatou/article/detail.

    2022年6月24日
    66

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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