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

Koala++'s blog

计算广告学 RTB

 
 
 

日志

 
 

Lucene源代码分析[-4]  

2009-07-08 08:26:08|  分类: Lucene |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

         我们接上次的IndexSearchersearch函数中的最后一个函数score

public void score(HitCollector hc) throws IOException {

    next();

    score(hc, Integer.MAX_VALUE);

}

    先看一下next函数:

public boolean next() throws IOException {

    pointer++;

    if (pointer >= pointerMax) {

       pointerMax = termDocs.read(docs, freqs); // refill buffer

       if (pointerMax != 0) {

           pointer = 0;

       } else {

           termDocs.close(); // close stream

           doc = Integer.MAX_VALUE; // set to sentinel value

           return false;

       }

    }

    doc = docs[pointer];

    return true;

}

    PointerpointerMax都没有进行初始化过,那我们直接看read函数:

public int read(final int[] docs, final int[] freqs) throws IOException {

    final int length = docs.length;

    int i = 0;

    while (i < length && count < df) {

       // manually inlined call to next() for speed

       final int docCode = freqStream.readVInt();

       doc += docCode >>> 1; // shift off low bit

       if ((docCode & 1) != 0) // if low bit is set

           freq = 1; // freq is one

       else

           freq = freqStream.readVInt(); // else read freq

       count++;

 

       if (deletedDocs == null || !deletedDocs.get(doc)) {

           docs[i] = doc;

           freqs[i] = freq;

           ++i;

       }

    }

    return i;

}

    看到这里,我感觉自己是不是在分析建索引的时候漏看了这个类,就先不管了,就在这里解决它,这里用了缓存,每次读32int。这个是在读.frq文件,回忆一个.frq文件中的值的形式,如果term就在这个doc中出现了一次,那么就是这个doc与前一个doc的差值右移一位再与1,即((doc-lastDoc)<<1)|1,而出现多于一次就是先写(doc-lastDoc)<<1,再写出现了多少次(tf),这里看到的是一个逆过程。并且我们也没有去删除文件。下面是判断我们找到的这个文档是不是已经删除过,你也许会想删除了,怎么还会搜索到,其实不是这样的,我们已经看到的commit函数就已经说明了这个问题,一般都把它与回收站做类比,你看起来是删除了,但是它其实在回收站里,只有你把它在回收站中删除时,它才真正消失了(准确地说,它还是存在的,只是看不到了)

    回到next函数,看到如果maxPointer如果不为0,也就是我们找到了含有这个termdocument,那么pointer就置0,再把doc的值赋为第一个文档的编号。

    再看score函数:

protected boolean score(HitCollector c, int end) throws IOException {

    Similarity similarity = getSimilarity(); // cache sim in local

    float[] normDecoder = Similarity.getNormDecoder();

    while (doc < end) { // for docs in window

       int f = freqs[pointer];

       float score = // compute tf(f)*weight

       f < SCORE_CACHE_SIZE // check cache

       ? scoreCache[f] // cache hit

       : similarity.tf(f) * weightValue; // cache miss

 

       score *= normDecoder[norms[doc] & 0xFF]; // normalize for field

 

       c.collect(doc, score); // collect score

 

       if (++pointer >= pointerMax) {

           pointerMax = termDocs.read(docs, freqs); // refill buffers

           if (pointerMax != 0) {

              pointer = 0;

           } else {

              termDocs.close(); // close stream

              doc = Integer.MAX_VALUE; // set to sentinel value

              return false;

           }

       }

       doc = docs[pointer];

    }

    return true;

}

    这里的getNormDecoder还没有见过:

public static float[] getNormDecoder() {

    return NORM_TABLE;

}

 

/** Cache of decoded bytes. */

private static final float[] NORM_TABLE = new float[256];

 

static {

    for (int i = 0; i < 256; i++)

       NORM_TABLE[i] = SmallFloat.byte315ToFloat((byte) i);

}

    注意那一行注释,和我们看tfcache32个值一样,这里cache256个值,这里注意的是一共就256个取值,所以就全部cache了。其中SmallFloat我们也是见过的,不过上次就不清楚是怎么算,这次也就不看了。

    回到score函数中,我们看到如果这个tf是在缓存里的,那么用从scoreCache中读出来,如果不在的话就要计算了,scoreCache里的值是象tfidf的值的表,但是它不是tfidf,具体的计算方式,可以看Javen Studio 咖啡小屋中的介绍,norm的值以前也介绍过,是field boost的值乘以1/sqrt(numTerms)。接着看,如果buffer中的值已经读完了,那么就重新读,pointer0,如果没有读完,那就读取下一个docdocs[pointer]

    docscore是用collect函数保存在c中的:

public void collect(int doc, float score) {

    if (score > 0.0f) {

       totalHits++;

       if (hq.size() < numHits || score >= minScore) {

           hq.insert(new ScoreDoc(doc, score));

           minScore = ((ScoreDoc) hq.top()).score; // maintain minScore

       }

    }

}

    这里的hq是一个PriorityQueue,这个类以前也见过,将它插入的时候,当然是比较它们的score了:

protected final boolean lessThan(Object a, Object b) {

    ScoreDoc hitA = (ScoreDoc) a;

    ScoreDoc hitB = (ScoreDoc) b;

    if (hitA.score == hitB.score)

       return hitA.doc > hitB.doc;

    else

       return hitA.score < hitB.score;

}

insert函数我们上次是没有见过的,这次只是列出来,不想讲了:

public boolean insert(Object element) {

    if (size < maxSize) {

       put(element);

       return true;

    } else if (size > 0 && !lessThan(element, top())) {

       heap[1] = element;

       adjustTop();

       return true;

    } else

       return false;

}

我们又可以回到IndexSearcher.search函数了,我们还剩下最后一个函数topDocs

/** The top-scoring hits. */

public TopDocs topDocs() {

    ScoreDoc[] scoreDocs = new ScoreDoc[hq.size()];

    for (int i = hq.size() - 1; i >= 0; i--)

       // put docs in array

       scoreDocs[i] = (ScoreDoc) hq.pop();

 

    float maxScore = (totalHits == 0) ? Float.NEGATIVE_INFINITY

           : scoreDocs[0].score;

 

    return new TopDocs(totalHits, scoreDocs, maxScore);

}

         这里可以看到还要求一个maxScore的值,scoreDocs中保存的是最高的score值,再看TopDocs函数:

TopDocs(int totalHits, ScoreDoc[] scoreDocs, float maxScore) {

    this.totalHits = totalHits;

    this.scoreDocs = scoreDocs;

    this.maxScore = maxScore;

}

         只是简单的赋值,我们再回到HitsgetMoreDocs

length = topDocs.totalHits;

ScoreDoc[] scoreDocs = topDocs.scoreDocs;

 

float scoreNorm = 1.0f;

 

if (length > 0 && topDocs.getMaxScore() > 1.0f) {

    scoreNorm = 1.0f / topDocs.getMaxScore();

}

         如果大于1,就用1除最大的score,下面用于归一化。我们看到最后的HitDoc类:

final class HitDoc {

    float score;

    int id;

    Document doc = null;

    HitDoc next; // in doubly-linked cache

    HitDoc prev; // in doubly-linked cache

 

    HitDoc(float s, int i) {

       score = s;

       id = i;

    }

}

         到这里已经基本上结束了,我们已经分析完了中间所遇到的所有函数。

 

 

 

 

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

历史上的今天

评论

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

页脚

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