Chinaunix首页 | 论坛 | 博客
  • 博客访问: 94510
  • 博文数量: 40
  • 博客积分: 651
  • 博客等级: 上士
  • 技术积分: 356
  • 用 户 组: 普通用户
  • 注册时间: 2011-08-08 22:31
文章分类

全部博文(40)

文章存档

2013年(6)

2012年(3)

2011年(31)

我的朋友

分类: Java

2013-03-21 22:14:15

基本上算是仿照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的字符串。


点击(此处)折叠或打开



  1. public
    class DefaultTokenizer extends Tokenizer{

  2.      /**JFlex扫描器*/ implements Word Break rules from the Unicode Text Segmentation algorithm,
  3.     private final StandardTokenizerImpl scanner;
  4.     /**从输入流字串中解析出的词元的各种信息*/
  5.     //词元的内容,如"tearcher" "xy12@yahoo.com" "1421"用来保存Token字符串;
  6.     private final org.apache.lucene.analysis.tokenattributes.CharTermAttribute termAtt ;
  7.     
  8.   //词元的首字母和尾字母在文本中的位置信息 用来保存偏移量信息。
  9.     private final org.apache.lucene.analysis.tokenattributes.OffsetAttribute offsetAtt ;
  10.     
  11.     //当前词元在TokenStream中相对于前一个token的位置,用于短语搜索 用来保存位置信息
  12.     private final org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute posIncrAtt ;

  13.     //词元所属的类别,,如
  14.     
  15.     private final org.apache.lucene.analysis.tokenattributes.TypeAttribute typeAtt ;

  16.    // CharTermAttribute 添加到Map中,并保存一个成员变量。
  17.     protected DefaultTokenizer(Version matchVersion,Reader input) {
  18.         super(input);
  19.         this.scanner = new StandardTokenizerImpl(input);
  20.         termAtt = addAttribute(CharTermAttribute.class);
  21.         offsetAtt = addAttribute(OffsetAttribute.class);
  22.         posIncrAtt = addAttribute(PositionIncrementAttribute.class);
  23.         typeAtt = addAttribute(TypeAttribute.class);
  24.         
  25.     }
  26.      public int posIncr;
  27.      //CachingTokenFilter file:///D:/e-book/%E6%8F%92%E4%BB%B6%20demo/lucene/lucene-4.2.0/docs/core/index.html
  28.     @Override
  29.     public boolean incrementToken() throws IOException {
  30.          clearAttributes();
  31.          int posIncr = 1;
  32.          
  33.          while(true) {
  34.              //通过JFlex扫描器scanner取得与规则相匹配的当前词元,否则返回-1
  35.              int tokenType = scanner.getNextToken();
  36.              
  37.              if (tokenType == StandardTokenizerImpl.YYEOF) {
  38.                  return false;
  39.              }
  40.              
  41.              if (scanner.yylength() <= 255){
  42.                  posIncrAtt.setPositionIncrement(posIncr);
  43.                  //将当前词元字串储记录在TermAttribute属性中,比如“I'm”
  44.                  scanner.getText(termAtt);
  45.                  //得到当前词元首字母在整个文本内容中的位置
  46.                  final int start = scanner.yychar();
  47.                //将当前词元的位置信息(开始位置,结束位置)记录在OffsetAttribute属性中
  48.                  offsetAtt.setOffset(correctOffset(start), correctOffset(start+termAtt.length()));
  49.                  
  50.                //确定当前词元的类别信息,并记录在TypeAttribute属性中
  51.                  typeAtt.setType(StandardTokenizer.TOKEN_TYPES[tokenType]);
  52.                  return true;         
  53.                 
  54.              }
  55.             
  56.          }
  57.         
  58.     }

  59. }
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) |
给主人留下些什么吧!~~