2021SC@SDUSC
今天继续对Lucene中的Analysis进行分析
阅读的DotLucene版本是1.9.RC1
在索引的时候,添加域的时候,可以指定Analyzer,使其生成TokenStream,也可以直接指定TokenStream:
public Field(String name, TokenStream tokenStream);
下面介绍两个单独使用的TokenStream
介绍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; } |
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 |