Lucene分词实现:Analyzer、TokenStream「建议收藏」

Lucene分词实现:Analyzer、TokenStream「建议收藏」Lucene分词实现(二次开发流程)1.1  分词流程在Lucene3.0中,对分词主要依靠Analyzer类解析实现。Analyzer内部主要通过TokenStream类实现。Tonkenizer类、TokenFilter类是TokenStream的两个子类。Tokenizer处理单个字符组成的字符流,读取Reader对象中的数据,处理后转换成词汇单元。Tokne

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

Lucene分词实现(二次开发流程)

1.1  分词流程

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

Lucene分词实现:Analyzer、TokenStream「建议收藏」

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实现:

TokenStream result = new StandardTokenizer(reader);//表示用StandardTokenizer对这个要分词的reader进行处理,然后返回一个TokenStream对象
result = new StandardFilter(result);//表示对生成的TokenStream对象进行标准过滤(Filter)
result = new LowerCaseFilter(result);//表示对上面由”StandardFilter”过滤后的TokenStream对象再进行次过滤,转化为小写

result = new StopFilter(result, stopSet);//接下来再进行次过滤,去掉停止词
5return 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对象中解析得出属性。

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 互联网裁员为什么专捡大于35的裁?

    互联网裁员为什么专捡大于35的裁?以前写过一篇文章《在中国程序员是青春饭吗?》,一时间,各个平台都成为爆文,在这篇文章中,详细讲解了程序员的青春饭问题,并且给出了具体地五个出路。第一条出路,说的是需要走技术专家路线。有些小伙伴就有疑问了,我年龄大了,我技术菜,就我不能降薪去小公司吗?就着这两年各个大厂对高龄程序员的种种限制,我们再来谈一谈,为什么我建议大家如果要走技术路线,就一定要进中大厂走技术专家的路线。记得帮我点赞哦。一、大厂裁员,为什么优先35岁以上?大道理总是无力的,先讲几个事实吧。为了避免不必要的.

    2022年7月17日
    16
  • 阅读书源最新2020在线导入_书源篇三及6.5.0版本介绍

    阅读书源最新2020在线导入_书源篇三及6.5.0版本介绍书源篇三及6.5.0版本介绍魔幻2020魔幻的2020,开启不一样的生活状态,作为一名技术宅,不出门虽我愿,但看到空荡荡的街头,心中却有种难言的难过与害怕。我不向往繁华。但喜欢车马如龙,街灯繁华。愿祖国强盛人长久,我辈身强振家兴!书源及工作原理书源:一个网站的规则描述文件,可能包括有多个来源;来源:聚合网站包括多个网站的内容,一个来源表示其中一个网站。仓库:存储书源的地方…

    2022年6月16日
    1.0K
  • 学习Oracle这一篇就够了

    学习Oracle这一篇就够了配套资料,免费下载链接:https://pan.baidu.com/s/1yjJY3IstA8aMQBPYhWNlCw提取码:qmpd复制这段内容后打开百度网盘手机App,操作更方便哦第一章数据库概述1.1、数据库的好处将数据持久化到本地提供结构化查询功能1.2、数据库的常见概念DB:数据库,存储数据的仓库DBMS:数据库管理系统,又称为数据库软件或者数据库产品,用于创建和管理数据库,常见的有MySQL、Oracle、SQLServerDBS:数据库系统,数据库系统是一个通称

    2022年10月8日
    0
  • android studio安装教程(包安装成功,不成功你找我)

    android studio安装教程(包安装成功,不成功你找我)百度搜索Androidstudio,或者直接输入http://www.android-studio.org进入这个页面根据这个下载相应的安装包或者压缩包。这里演示安装64位的androidstudio下载完成后直接双击安装包,就会出来下面这个界面点击Next点击Next点击Next点击i…

    2022年6月28日
    20
  • pycharm mac激活码2022(JetBrains全家桶)

    (pycharm mac激活码2022)2021最新分享一个能用的的激活码出来,希望能帮到需要激活的朋友。目前这个是能用的,但是用的人多了之后也会失效,会不定时更新的,大家持续关注此网站~https://javaforall.net/100143.htmlIntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,上面是详细链接哦~4K…

    2022年4月1日
    743
  • 01字典树 详解「建议收藏」

    01字典树 详解「建议收藏」欢迎关注我的个人博客:www.zuzhiang.cn以前只知道字典树可以降低空间复杂度,今天无意中接触了01字典树,原来可以用它来降低时间复杂度,下面我就来给大家介绍一下01字典树的原理和应用。01字典树主要用于解决求异或最值的问题。我先放上简单的模板,然后再讲解它的原理。inttol;//节点个数LLval[32*MAXN];//点的值i…

    2022年9月7日
    0

发表回复

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

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