注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Koala++'s blog

计算广告学 RTB

 
 
 

日志

 
 

Lucene源代码分析[8]  

2009-07-03 15:01:33|  分类: Lucene |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

// add an entry to the dictionary with pointers to prox and freq files

ti.set(1, freq.getFilePointer(), prox.getFilePointer(), -1);

tis.add(posting.term, ti);

ti是一个TermInfo对象,不介绍了,下面看一下add函数:

final void add(Term term, TermInfo ti) throws IOException {

if (!isIndex && size % indexInterval == 0)

    other.add(lastTerm, lastTi); // add an index term

   

    writeTerm(term); // write term

    output.writeVInt(ti.docFreq); // write doc freq

    output.writeVLong(ti.freqPointer - lastTi.freqPointer);

    output.writeVLong(ti.proxPointer - lastTi.proxPointer);

 

    if (ti.docFreq >= skipInterval) {

       output.writeVInt(ti.skipOffset);

    }

 

    if (isIndex) {

       output.writeVLong(other.output.getFilePointer() –

lastIndexPointer);

       lastIndexPointer = other.output.getFilePointer();

    }

 

    lastTi.set(ti);

    size++;

}

    再把writeTerm函数列出来:

private final void writeTerm(Term term) throws IOException {

    int start = StringHelper.stringDifference(lastTerm.text, term.text);

    int length = term.text.length() - start;

 

    output.writeVInt(start); // write shared prefix length

    output.writeVInt(length); // write delta length

    output.writeChars(term.text, start, length); // write delta chars

 

    output.writeVInt(fieldInfos.fieldNumber(term.field));

    lastTerm = term;

}

    没有办法,第一个函数又不知所云,接着列:

public static final int stringDifference(String s1, String s2) {

    int len1 = s1.length();

    int len2 = s2.length();

    int len = len1 < len2 ? len1 : len2;

    for (int i = 0; i < len; i++) {

        if (s1.charAt(i) != s2.charAt(i)) {

           return i;

       }

    }

    return len;

}

    这个函数名硬译出来是字符串差异,而它其实是返回的是字符串最前面相同的长度。

    我们回到writeTerm函数,它将求得的开头相同字符长度写入,再写入,不相同字符串的长度,再写不相同的长度写入,最后写入Field的序号。

    我们回到add函数,docFreqfreqPointerproxPointer,下面有一个上次没有讲的skipIntervalExpert: The fraction of TermDoc entries stored in skip tables, used to accellerate TermDocs.skipTo(int). Larger values result in smaller indexes, greater acceleration, but fewer accelerable cases, while smaller values result in bigger indexes, less acceleration and more accelerable cases. More detailed experiments would be useful here. 看起来与TermDocs.skipTo有关系,但是我们还没有遇见过个函数,我联想到的就是Introduction to information retrieval36页的那幅图。

    现在我们看一下这个函数是如何被调用的,第一个ifisIndexfalse并且sizeindexInterval的倍数时才执行,所执行的函数是add本身,因为other本身也是一个TermInfos但它的isIndextrue,所以不会执行死循环,它将lastTermlastTi保存起来,再执行(isIndex)中的语句。indexInterval的注释是The fraction of terms in the "dictionary" which should be stored in RAM. Smaller values use more memory, but make searching slightly faster, while larger values use less memory and make searching slightly slower. Searching is typically not dominated by dictionary lookup, so tweaking this is rarely useful.

    在讲下面的内容之前,把FieldTest中的内容换成:

Document doc1 = new Document();

Field name1 = new Field( "TheField", "hello world hello china",

    Field.Store.YES, Field.Index.TOKENIZED );

doc1.add( name1 );

    我把余下的代码分开列出来:

// add an entry to the freq file

int postingFreq = posting.freq;

if (postingFreq == 1) // optimize freq=1

    freq.writeVInt(1); // set low bit of doc num.

else {

    freq.writeVInt(0); // the document number

    freq.writeVInt(postingFreq); // frequency in doc

}

 

int lastPosition = 0; // write positions

int[] positions = posting.positions;

for (int j = 0; j < postingFreq; j++) { // use delta-encoding

    int position = positions[j];

    prox.writeVInt(position - lastPosition);

    lastPosition = position;

}

    这里看起来对文档频率等于1的值进行了特殊处理,而在保存位置信息的时候所保存的是与上一个position之间的差值。

// check to see if we switched to a new field

String termField = posting.term.field();

if (currentField != termField) {

    // changing field - see if there is something to save

    currentField = termField;

    FieldInfo fi = fieldInfos.fieldInfo(currentField);

    if (fi.storeTermVector) {

       if (termVectorWriter == null) {

           termVectorWriter = new TermVectorsWriter(directory,

                  segment, fieldInfos);

           termVectorWriter.openDocument();

       }

       termVectorWriter.openField(currentField);

 

    } else if (termVectorWriter != null) {

       termVectorWriter.closeField();

    }

}

if (termVectorWriter != null && termVectorWriter.isFieldOpen()) {

    termVectorWriter.addTerm(posting.term.text(), postingFreq,

           posting.positions, posting.offsets);

}

    这一段是看是不是又换了一个新的Field,但是我们没有设置storeTermVector,这里不做理睬。

    其实还有一个值得注意的函数,记得我们在产生tistii的时候写入的字节吗?

output.writeInt(FORMAT); // write format

output.writeLong(0); // leave space for size

output.writeInt(indexInterval); // write indexInterval

output.writeInt(skipInterval); // write skipInterval

    Format-2int0longindexInterval128intskipInterval16int。一共是20个字节,我们tistii的前20个字节取出来看一下:

FF FF FF FE 00 00 00 00 00 00 00 00 06 00 00 00 80

00 00 00 10 00

FF FF FF FE 00 00 00 00 00 00 00 00 01 00 00 00 80

00 00 00 10 00

    两个函数都用的是initialize而且第二个写入的都是0,为什么一个是6一个是1呢?其实tis对象最后调用了close函数:

final void close() throws IOException {

    output.seek(4); // write size after format

    output.writeLong(size);

    output.close();

 

    if (!isIndex)

       other.close();

}

    我们可以看到最后把0改成了size,我的tis一共有6个词:bonjourmondechinafrancehelloworld。而tiisize1

    我把余下的tii内容列出来:

FF FF FF FE 00 00 00 00 00 00 00 00 01 00 00 00 80

00 00 00 10 00 00 00 FF FF FF FF 0F 00 00 00 14

    我用红色标记出来了,前两个00 00wirteTerm写入的,writeTerm中的第三个函数writeChars其实什么都没有写入,因为长度为0FF FF FF FF 0FwriteTerm中第四个函数写入的,因为这个term为空,所以它没有对应的Field,找不到它的Field就返回-1

为什么-1表示成这个原因为,倒着看,每七位断开:

1111 1111 1111 1111 1111 1111 1111 1111  

可以看到最前面还剩下了1111当然它就是0F,其它300就不讲了,最后14是表示tis开始的位置是14(十进制20)

每个项信息索引文件包含.tis文件中的indexInterval个条目,依照条目在.tis文件中的顺序。这样设计是为了一次将索引信息读入内存能,然后使用它来随机的访问.tis文件。

    是不是有看再看完tis是如何产生就大功告成的想法呢?其实上面讲的也不对,因为我们一共写了3Field为什么这里就一个呢?原因是它根本就不是这样写出来的,一个玩笑而已。

    还记得我们Document.addDocument中还有一个函数没看吗?

// write norms of indexed fields

writeNorms(segment);

    列出这个函数:

private final void writeNorms(String segment) throws IOException {

    for (int n = 0; n < fieldInfos.size(); n++) {

       FieldInfo fi = fieldInfos.fieldInfo(n);

       if (fi.isIndexed && !fi.omitNorms) {

           float norm = fieldBoosts[n]

                  * similarity.lengthNorm(fi.name, fieldLengths[n]);

           IndexOutput norms = directory.createOutput(segment + ".f"

+ n);

           try {

              norms.writeByte(Similarity.encodeNorm(norm));

           } finally {

              norms.close();

           }

       }

    }

}

    这里的boost是对Field重要性的一种设置,默认值是1lengthNorm也差不多,它相对好理解一点,就是这个Field值中的term超多,那么它的值就越低。代码如下:

public float lengthNorm(String fieldName, int numTerms) {

    return (float) (1.0 / Math.sqrt(numTerms));

}

    下面的一个函数encodeNorm我看了一下,只知道它是把一个float变成一个byte保存,并不明白为什么那样写。Google了一下,也没找到。很遗憾,这个文件没法分析了。

 

 

  评论这张
 
阅读(1194)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017