博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Lucene学习二次开发之——分词开发流程
阅读量:5281 次
发布时间:2019-06-14

本文共 7180 字,大约阅读时间需要 23 分钟。

最近没什么事情可做,于是就看了看Lucene源码,以往版本Lucene的各个功能都是合在一个jar 包的,

最近发布4.0,4.1 就将各个功能都分开了

首先对分词(分析)部分进行了学习

说是分词,更准确的应该叫分析, 主要指将域(Field)文本转换为最基本的索引表示单元 ——项(Term) 的过程。

这些操作包括:提取单词,去掉标点,将字母转换为小写,去除常用词(停用词),将单词还原为词干…………

   Token(单个词信息) 和他所在域(Filed)结合后就是项——term

   多个Term 组成了Field

分词流程:

在Lucene中,对分词主要依靠Analyzer类解析实现。Analyzer内部主要通过TokenStream类实现。

Tonkenizer类、TokenFilter类是TokenStream的两个子类。

Tokenizer处理单个字符组成的字符流,读取Reader对象中的数据,处理后转换成词汇单元。

TokneFilter完成文本过滤器的功能,但在使用过程中必须注意不同的过滤器的使用的顺序。

Analyzer  

他下面有几个重要的方法

 (3.x版本中):

 (1) 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对象;

  (2) public TokenStream reusableTokenStream(String fieldName, Reader reader)

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

  (4.0—1 版本)

    (1)TokenStreamComponents createComponents(String fieldName, Reader reader)

 

实现他的方法有(这是从3.x 的api上摘的,但在源码里好像没有这些类 像SmartChineseAnalyzer  看了下api 貌似是中科院imdict继承的,  4.x 版本中证实了想法,把这个都放在了lucene-analyzers-common-4.1.0.jar包里了 ):

CollationKeyAnalyzer, ICUCollationKeyAnalyzer, LimitTokenCountAnalyzer, MockAnalyzer, PerFieldAnalyzerWrapper,QueryAutoStopWordAnalyzer,

 QueryParserTestBase.QPTestAnalyzer, ReusableAnalyzerBase, ShingleAnalyzerWrapper, SmartChineseAnalyzer,SnowballAnalyzer

在(4.x 的版本中实现他的方法就只有AnalyzerWrapper

 Lucene 自带的几个分词器

    继承自ReusableAnalyzerBase

   WhitespaceAnalyzer  这是根据空格分割的

   SimpleAnalyzer   他是先根据非字母字符来分割,并且将字符转换为小写,这个分词器会去掉数字类型的字符

  

TokenStream

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

(1)获取下一Token;

         public abstract boolean incrementToken() throws IOException;

(2)重设流(可选);public void reset() throws IOException

(3)关闭流,释放资源;public void close() throws IOException

实现他的方法Lucene自带的有

CannedTokenStream, CategoryAttributesStream, EmptyTokenStream, NumericTokenStream, PrefixAndSuffixAwareTokenFilter,PrefixAwareTokenFilter,

 ShingleMatrixFilter, SingleTokenTokenStream, TeeSinkTokenFilter.SinkTokenStream, TokenFilter, Tokenizer,TokenStreamFromTermPositionVector

Token

 该类继承了一个类

 TermAttributeImpl

 实现了

  TypeAttribute  表示token的字符串信息

  PositionIncrementAttribute  表示token词典类别信息,默认为“Word”,

  FlagsAttribute   用于在Tokenizer链之前传递标记(因为前面一个操作可能会影响后面的操作)。那么这个属性有什么用呢,用处很大的。加入我们想搜索一个短语student apples(假如有这个短语)。很显然,用户是要搜索出student apples紧挨着出现的文档。这个时候我们找到了某一篇文档(比如上面例子的字符串)都含有student apples。但是由于apples的PositionIncrementAttribute值是5,说明肯定没有紧挨着。

  OffsetAttribute   表示token的首字母和尾字母在原文本中的位置,需要注意的是startOffset与endOffset的差值并不一定就是termText.length(),因为可能term已经用过滤器处理过

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

  PositionLengthAttribute   它表示tokenStream中的当前token与前一个token在实际的原文本中相隔的词语数量,用于短语查询。

 Tokenizer

 继承了TokenStream类 该类主要是接收输入流并根据输入流进行词切分。虽然她本身是个抽象类,但是定制分词器的核心之一。

 实现的子类有很多

 Lucene自带的就有:

CharTokenizer, ChineseTokenizer, CJKTokenizer, ClassicTokenizer, EdgeNGramTokenizer, EmptyTokenizer, ICUTokenizer,JapaneseTokenizer, KeywordTokenizer, 

MockTokenizer, NGramTokenizer, PathHierarchyTokenizer, ReversePathHierarchyTokenizer,SentenceTokenizer, StandardTokenizer, UAX29URLEmailTokenizer, WikipediaTokenizer

 TokenFilter

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

实现他的子类很多不过一般实用的类有 对空格过滤,停止词过滤,

实现他的子类有:

ArabicNormalizationFilter, ArabicStemFilter, ASCIIFoldingFilter, BeiderMorseFilter, BrazilianStemFilter, BulgarianStemFilter,CachingTokenFilter,

 CategoryParentsStream, CategoryTokenizerBase, ChineseFilter, CJKBigramFilter, CJKWidthFilter, ClassicFilter,CollationKeyFilter, CompoundWordTokenFilterBase, 

CzechStemFilter, DelimitedPayloadTokenFilter, DoubleMetaphoneFilter,DutchStemFilter, EdgeNGramTokenFilter, ElisionFilter, 

EnglishMinimalStemFilter, EnglishPossessiveFilter, FilteringTokenFilter,FinnishLightStemFilter, FrenchLightStemFilter, FrenchMinimalStemFilter,

 FrenchStemFilter, GalicianMinimalStemFilter,GalicianStemFilter, GermanLightStemFilter, GermanMinimalStemFilter, GermanNormalizationFilter,

 GermanStemFilter,GreekLowerCaseFilter, GreekStemFilter, HindiNormalizationFilter, HindiStemFilter, HungarianLightStemFilter, 

HunspellStemFilter,ICUCollationKeyFilter, ICUNormalizer2Filter, ICUTransformFilter, IndicNormalizationFilter,

 IndonesianStemFilter,IrishLowerCaseFilter, ISOLatin1AccentFilter, ItalianLightStemFilter, JapaneseBaseFormFilter, 

JapaneseKatakanaStemFilter,JapaneseReadingFormFilter, KeywordMarkerFilter, KStemFilter, LatvianStemFilter, 

LimitTokenCountFilter, LookaheadTokenFilter,LowerCaseFilter, MockFixedLengthPayloadFilter, MockHoleInjectingTokenFilter,

 MockVariableLengthPayloadFilter, NGramTokenFilter,NorwegianLightStemFilter, NorwegianMinimalStemFilter, NumericPayloadTokenFilter,

 OffsetLimitTokenFilter, PersianNormalizationFilter,PhoneticFilter, PorterStemFilter, PortugueseLightStemFilter, PortugueseMinimalStemFilter, 

PortugueseStemFilter, PositionFilter,QueryParserTestBase.QPTestFilter, ReverseStringFilter, RussianLightStemFilter, RussianLowerCaseFilter, 

RussianStemFilter,ShingleFilter, SnowballFilter, SpanishLightStemFilter, StandardFilter, StemmerOverrideFilter, StempelFilter, 

SwedishLightStemFilter,SynonymFilter, TeeSinkTokenFilter, ThaiWordFilter, TokenOffsetPayloadTokenFilter, TurkishLowerCaseFilter,

 TypeAsPayloadTokenFilter,ValidatingTokenFilter, WordTokenFilter

 知道了Lucene分词的核心方法分词扩展就比较容易了

 我自己将以前的分词器继承了4.x

下面是输出代码:

public String ordinaryAnalyzer(String string) {        Analyzer analyzer = new MyAnalyzer(Version.LUCENE_41);        TokenStream ts = null;        StringBuffer sb = new StringBuffer();        try {            ts = analyzer.tokenStream("sentence", new StringReader(string));            CharTermAttribute term = ts.addAttribute(CharTermAttribute.class);            ts.reset();            while (ts.incrementToken()) {                if (term.toString().equals(" ")) {                } else {                    sb.append(term.toString() + " ");                }            }            ts.end();        } catch (IOException e) {            e.printStackTrace();        } finally {            if (ts != null) {                try {                    ts.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }        return sb.toString().trim();    }

你还可以加入别的信息 开始位置,结束位置,还有type

public class TestFenci {    public static void main(String[] args) {        ChineseAnalyzer as = new ChineseAnalyzer();        long startTime = System.currentTimeMillis();        String sentence = "男 包北京海淀";        as.wordAnalyzer(sentence);        System.out.println("挑出地址:" + as.pickCityAnalyzer(sentence));        System.out.println("普通分开:" + as.ordinaryAnalyzer(sentence));        System.out.println("加扩展:" + as.expandAnalyzer(sentence));        System.out.print(System.currentTimeMillis() - startTime);    }}

结果:

0 - 1 : 男 | word

1 - 2 :   | word
2 - 3 : 包 | word
3 - 5 : 北京 | word
5 - 7 : 海淀 | word
挑出地址:key:男 包 address:北京 海淀 guess:
普通分开:男 包 北京 海淀
加扩展:男 or 男士 or 男式 or 男生 包 or 包包 北京 海淀
94

转载于:https://www.cnblogs.com/tomcattd/archive/2013/01/29/2881197.html

你可能感兴趣的文章
python - 使用psutils
查看>>
MyBatis 一、二级缓存和自定义缓存
查看>>
Linux如何查看进程、杀死进程、启动进程等常用命令
查看>>
poj 1392 Ouroboros Snake
查看>>
使用kdesvn提交文件出现Aborting commit:'.lcd1602.ko.cmd' remains in conflict错误提示
查看>>
解决Jenkins无法编译Egret5.0项目的问题
查看>>
declare 结构用来设定一段代码的执行指令
查看>>
Hadoop学习笔记三:分布式hadoop部署
查看>>
异步IO和同步IO的区别:
查看>>
C 预处理指令
查看>>
动态规划求最大连续字序列
查看>>
ADO.Net---复习基础篇1
查看>>
图解算法读书笔记
查看>>
ubuntu 通过ppa源安装mysql5.6
查看>>
调试学习笔记
查看>>
连载 11:如何把信号展开成复指数信号之 和?
查看>>
解开lambda最强作用的神秘面纱
查看>>
Java基础:Object类中的equals与hashCode方法
查看>>
C#拦截Http请求
查看>>
转:enum与typedef enum的用法
查看>>