基本上算是仿照StandardTokenizer来实现的
4.0,3.0之后和2.0Tokenizer的实现有了很大的区别
Lucene 3.0之后发生了很大的变化。
Tokenizer 继承TokenStream,主要有两个方法
public boolean incrementToken(){}用于得到下一个token
public void reset(){}重置该分词器,使得此TokenStrean可以重新开始返回各个分词。
scanner是StandardTokenizerImpl类初始化的对象,这个对象里存储了扫描输入流字串得到的词元信息(词元的内容、长度、所属的类别、所在位置等)。它没有用next()方法直接得到TokenStream的下一个词元内容而是使用incrementToken()方法将每一个scanner.getNextToken()的各种词元信息保存在不同类型的Attribute里面,
i比如CharTermAttribute(除了支持中文字符型的CharTermAttribute还有
等)用于保存词元的内容,TyteAttribute用于保存词元的类型。
3.0是如何保存下一个Token信息的呢?
在Lucene 3.0中,TokenStream是继承于AttributeSource,其包含Map,保存从class到对象的映射,从而可以保存不同类型的对象的值。
在TokenStream中,经常用到的对象是
CharTermAttribute(或者用接口的实现类),用来保存Token字符串;
PositionIncrementAttribute 用来保存位置信息,;
OffsetAttribute用来保存偏移量信息。
TypeAttribute用来保存Token的类型,如
,对应的值是10,是表意字,也就是中文。
然后
在incrementToken()中,将下一个Token的信息写入当前的tokenAtt,然后使用CharTermAttributeImpl.term()得到Token的字符串。
-
-
public class DefaultTokenizer extends Tokenizer{
-
-
/**JFlex扫描器*/ implements Word Break rules from the Unicode Text Segmentation algorithm,
-
private final StandardTokenizerImpl scanner;
-
/**从输入流字串中解析出的词元的各种信息*/
-
//词元的内容,如"tearcher" "xy12@yahoo.com" "1421"用来保存Token字符串;
-
private final org.apache.lucene.analysis.tokenattributes.CharTermAttribute termAtt ;
-
-
//词元的首字母和尾字母在文本中的位置信息 用来保存偏移量信息。
-
private final org.apache.lucene.analysis.tokenattributes.OffsetAttribute offsetAtt ;
-
-
//当前词元在TokenStream中相对于前一个token的位置,用于短语搜索 用来保存位置信息
-
private final org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute posIncrAtt ;
-
-
//词元所属的类别,,如、、
-
-
private final org.apache.lucene.analysis.tokenattributes.TypeAttribute typeAtt ;
-
-
// 将CharTermAttribute 添加到Map中,并保存一个成员变量。
-
protected DefaultTokenizer(Version matchVersion,Reader input) {
-
super(input);
-
this.scanner = new StandardTokenizerImpl(input);
-
termAtt = addAttribute(CharTermAttribute.class);
-
offsetAtt = addAttribute(OffsetAttribute.class);
-
posIncrAtt = addAttribute(PositionIncrementAttribute.class);
-
typeAtt = addAttribute(TypeAttribute.class);
-
-
}
-
public int posIncr;
-
//CachingTokenFilter file:///D:/e-book/%E6%8F%92%E4%BB%B6%20demo/lucene/lucene-4.2.0/docs/core/index.html
-
@Override
-
public boolean incrementToken() throws IOException {
-
clearAttributes();
-
int posIncr = 1;
-
-
while(true) {
-
//通过JFlex扫描器scanner取得与规则相匹配的当前词元,否则返回-1
-
int tokenType = scanner.getNextToken();
-
-
if (tokenType == StandardTokenizerImpl.YYEOF) {
-
return false;
-
}
-
-
if (scanner.yylength() <= 255){
-
posIncrAtt.setPositionIncrement(posIncr);
-
//将当前词元字串储记录在TermAttribute属性中,比如“I'm”
-
scanner.getText(termAtt);
-
//得到当前词元首字母在整个文本内容中的位置
-
final int start = scanner.yychar();
-
//将当前词元的位置信息(开始位置,结束位置)记录在OffsetAttribute属性中
-
offsetAtt.setOffset(correctOffset(start), correctOffset(start+termAtt.length()));
-
-
//确定当前词元的类别信息,并记录在TypeAttribute属性中
-
typeAtt.setType(StandardTokenizer.TOKEN_TYPES[tokenType]);
-
return true;
-
-
}
-
-
}
-
-
}
-
-
}
Lucene的英文分词器使用了JFlex的词法扫描方法。其具体实现在初始化StandardTokenizerImpl类时,通过调用类中的静态方法和StandardTokenizerImpl.jflex词法描述文件来一起解析待分词的输入流。并将最后扫描出来的词语分成
这几类,注意不是StandardTokenizer中的Token的类型做区分
在前面讲 StandardTokenizer的的时候,我们已经谈到了token的这四种属性。在这里我们再次强调一下这些Lucene的基础知识。
Lucene 3.0之后,TokenStream中的每一个token不再用next()方法返回,而是采用了incrementToken()方法(具体参见上面)。每调用一次incrementToken(),都会得到token的四种属性信息(org.apache.lucene.analysis.tokenattributes包中):
如上例:
原文本:I'm a student. these are apples
TokenSteam: [1: I'm ] [2:a] [3:student] [4:these] [5:are ] [6:apples]
这里插一句,估计会有人问,分词器是内部是如何,按照什么规则进行分词的,这里大概的解释下,
首先、分词器会从自己查询内容缓存到分词器的的待处理缓存中,字符by字符的读入,当遇到特殊字符,或标点符号时候,停止读入,进行处理。
举个栗子---格格格格-----'我一个' 三个字
分词器会选取和第一个字'我'匹配的所有短语并按照字符个数进行排序,例如'我好','我啊'.......巴拉巴拉
进行正则或者采用正向、二、逆向最大匹配法等。。。。。 http://blog.chinaunix.net/uid-26148869-id-3537963.html
就得到一个token字符串了,
在4.0中 调用 scanner.getText(termAtt); 的时候其实就获取该attribute中的前词元字串储记录了。
(1) TermAttribute: 表示token的字符串信息。比如"I'm"
(2) TypeAttribute: 表示token的类别信息(在上面讲到)。比如 I'm 就属于,有撇号的类型
(3) OffsetAttribute:表示token的首字母和尾字母在原文本中的位置。比如 I'm 的位置信息就是(0,3)
(4) PositionIncrementAttribute:这个有点特殊,它表示tokenStream中的当前token与前一个token在实际的原文本中相隔的词语数量。
比如: 在tokenStream中[2:a] 的前一个token是[1: I'm ] ,它们在原文本中相隔的词语数是1,则token="a"的PositionIncrementAttribute值为1。如果token是原文本中的第一个词,则默认值为1。因此上面例子的PositionIncrementAttribute结果就全是1了。
如果我们使用停用词表来进行过滤之后的话:TokenSteam就会变成: [1: I'm ] [2:student] [3:apples]这时student的PositionIncrementAttribute值就不会再是1,而是与[1: I'm ]在原文本中相隔词语数量=2。而apples则变成了5。
那么这个属性有什么用呢,用处很大的。加入我们想搜索一个短语student apples(假如有这个短语)。很显然,用户是要搜索出student apples紧挨着出现的文档。这个时候我们找到了某一篇文档(比如上面例子的字符串)都含有student apples。但是由于apples的PositionIncrementAttribute值是5,说明肯定没有紧挨着。怎么样,用处很大吧。轻而易举的解决了短语搜索的难题哦。
阅读(6527) | 评论(0) | 转发(0) |