Lucene代码分析9

2021SC@SDUSC

今天继续对Lucene中的Analysis进行分析

阅读的DotLucene版本是1.9.RC1

在索引的时候,添加域的时候,可以指定Analyzer,使其生成TokenStream,也可以直接指定TokenStream:

public Field(String name, TokenStream tokenStream);

下面介绍两个单独使用的TokenStream

1、NumericTokenStream

介绍NumericRangeQuery的时候,在生成NumericField的时候,其会使用NumericTokenStream,其incrementToken如下:

public boolean incrementToken() {

  if (valSize == 0)

    throw new IllegalStateException("call set???Value() before usage");

  if (shift >= valSize)

    return false;

  clearAttributes();

  //虽然NumericTokenStream欲保存数字,然而Lucene的Token只能保存字符串,因而要将数字编码为字符串,然后存入索引。

  final char[] buffer;

  switch (valSize) {

    //首先分配TermBuffer,然后将数字编码为字符串

    case 64:

      buffer = termAtt.resizeTermBuffer(NumericUtils.BUF_SIZE_LONG);

      termAtt.setTermLength(NumericUtils.longToPrefixCoded(value, shift, buffer));

      break;

    case 32:

      buffer = termAtt.resizeTermBuffer(NumericUtils.BUF_SIZE_INT);

      termAtt.setTermLength(NumericUtils.intToPrefixCoded((int) value, shift, buffer));

      break;

    default:

      throw new IllegalArgumentException("valSize must be 32 or 64");

  }

  typeAtt.setType((shift == 0) ? TOKEN_TYPE_FULL_PREC : TOKEN_TYPE_LOWER_PREC);

  posIncrAtt.setPositionIncrement((shift == 0) ? 1 : 0);

  shift += precisionStep;

  return true;

}

public static int intToPrefixCoded(final int val, final int shift, final char[] buffer) {

  if (shift>31 || shift<0)

    throw new IllegalArgumentException("Illegal shift value, must be 0..31");

  int nChars = (31-shift)/7 + 1, len = nChars+1;

  buffer[0] = (char)(SHIFT_START_INT + shift);

  int sortableBits = val ^ 0x80000000;

  sortableBits >>>= shift;

  while (nChars>=1) {

    //int按照每七位组成一个utf-8的编码,并且字符串大小比较的顺序同int大小比较的顺序完全相同。

    buffer[nChars--] = (char)(sortableBits & 0x7f);

    sortableBits >>>= 7;

  }

  return len;

}

2、SingleTokenTokenStream

SingleTokenTokenStream顾名思义就是此TokenStream仅仅包含一个Token,多用于保存一篇文档仅有一个的信息,如id,如time等,这些信息往往被保存在一个特殊的Token(如ID:ID, TIME:TIME)的倒排表的payload中的,这样可以使用跳表来增加访问速度。

所以SingleTokenTokenStream返回的Token则不是id或者time本身,而是特殊的Token,"ID:ID", "TIME:TIME",而是将id的值或者time的值放入payload中。

//索引的时候

int id = 0; //用户自己的文档号

String tokenstring = "ID";

byte[] value = idToBytes(); //将id装换为byte数组

Token token = new Token(tokenstring, 0, tokenstring.length);

token.setPayload(new Payload(value));

SingleTokenTokenStream tokenstream = new SingleTokenTokenStream(token);

Document doc = new Document();

doc.add(new Field("ID", tokenstream));

……

//当得到Lucene的文档号docid,并不想构造Document对象就得到用户的文档号时

TermPositions tp = reader.termPositions("ID:ID");

boolean ret = tp.skipTo(docid);

tp.nextPosition();

int payloadlength = tp.getPayloadLength();

byte[] payloadBuffer = new byte[payloadlength];

tp.getPayload(payloadBuffer, 0);

int id = bytesToID(); //将payloadBuffer转换为用户id

 

上一篇:[转载] DRM 简介


下一篇:Magarose-NHS,NHS活化琼脂糖磁珠,NHS琼脂糖微球预活化的琼脂糖磁性微球