Lucene Scoring 评分机制 ( by quqi99 )

Lucene Scoring 评分机制 ( by quqi99 )



Lucene Scoring 评分机制 http://blog.chenlb.com/2009/08/lucene-scoring-architecture.html


首先来看下 lucene 的评分公式(在 Similarity 类里的说明)

score(q,d) = coord(q,d) ·queryNorm(q) · ( tf(t in d) ·idf(t)2 ·t.getBoost() ·norm(t,d) )
t in q

其中:

  1. tf(t in d) 关联到项频率,项频率是指 t 在 文档 d 中出现的次数 frequency。默认的实现是:
    tf(t in d) = frequency½
  2. idf(t) 关联到反转文档频率,文档频率指出现 t 的文档数docFreq。docFreq 越少 idf 就越高(物以稀为贵),但在同一个查询下些值是相同的。默认实现:
    idf(t) = 1 + log(
    numDocs
    –––––––––
    docFreq+1
    )
  3. coord(q,d) 评分因子,是基于文档中出现查询项的个数。越多的查询项在一个文档中,说明些文档的匹配程序越高。默认是出现查询项的百分比。
  4. queryNorm(q) 查询的标准查询,使不同查询之间可以比较。此因子不影响文档的排序,因为所有有文档都会使用此因子。默认值:
    queryNorm(q) = queryNorm(sumOfSquaredWeights) =
    1
    ––––––––––––––
    sumOfSquaredWeights ½

    每个查询项权重的平分方和(sumOfSquaredWeights)由 Weight 类完成。例如 BooleanQuery 地计算:

    sumOfSquaredWeights = q.getBoost() 2 · ( idf(t) ·t.getBoost() )2
    t in q
  5. t.getBoost() 查询时期的 项 t 加权(如:java^1.2),或者由程序使用 setBoost()。
  6. norm(t,d) 压缩几个索引期间的加权和长度因子:
    • Document boost - 文档加权,在索引之前使用 doc.setBoost()
    • Field boost - 字段加权,也在索引之前调用 field.setBoost()
    • lengthNorm(field) - 由字段内的 Token 的个数来计算此值,字段越短,评分越高,在做索引的时候由 Similarity.lengthNorm 计算。
    以上所有因子相乘得出 norm 值,如果文档中有相同的字段,它们的加权也会相乘:
    norm(t,d) = doc.getBoost() ·lengthNorm(field) · f.getBoost()
    fieldf ind named ast

    索引的时候,把 norm 值压缩(encode)成一个 byte 保存在索引中。搜索的时候再把索引中 norm 值解压(decode)成一个 float 值,这个 encode/decode 由 Similarity 提供。官方说:这个过程由于精度问题,以至不是可逆的,如:decode(encode(0.89)) = 0.75。

/**
* 利用IndexReader获取下列信息,注意,建索引时需加Field.TermVector.YES:
(1) 统计term在整个collection中的文档频度(document frequency, DF);
(2) 统计term在整个collection中出现的词次(term frequency in whole collection);
(3) 统计term在某个文档中出现的频度(term frequency, TF);
(4) 列出term在某文档中出现的位置(position);
(5) 整个collection中文档的个数;
*/
public static void printIndex(IndexReader reader) throws Exception
{
// 显示有多少个document
System.out.println(reader + "\tNumDocs = " + reader.numDocs());
for (int i = 0; i < reader.numDocs(); i++)
{
System.out.println(reader.document(i));
}

// 枚举term,获得<document, term freq, position* >信息
TermEnum termEnum = reader.terms();
while (termEnum.next())
{
System.out.println(termEnum.term());
System.out.println("\tDocFreq=" + termEnum.docFreq());

TermPositions termPositions = reader.termPositions(termEnum.term());
int i = 0;
int j = 0;
while (termPositions.next())
{
System.out.println((i++) + "->" + " DocNo:" + termPositions.doc() + ", Freq:" + termPositions.freq());
for (j = 0; j < termPositions.freq(); j++)
System.out .println("[" + termPositions.nextPosition() + "]");
System.out.println();
}

// 直接获取 <term freq, document> 的信息
TermDocs termDocs = reader.termDocs(termEnum.term());
while (termDocs.next())
{
System.out.println((i++) + "->" + " DocNo:" + termDocs.doc() + ", Freq:" + termDocs.freq());
}
}

//在reader是SegmentReader类型的情况下有效
// FieldInfos fieldInfos = reader.fieldInfos;
// FieldInfo pathFieldInfo = fieldInfos.FieldInfo("path");

// 显示 term frequency vector
for (int i = 0; i < reader.numDocs(); i++)
{
// 对contents的token之后的term存于了TermFreqVector
TermFreqVector termFreqVector = reader.getTermFreqVector(i,"contents");
if (termFreqVector == null)
{
System.out.println("termFreqVector is null.");
continue;
}
String fieldName = termFreqVector.getField();
String[] terms = termFreqVector.getTerms();
int[] frequences = termFreqVector.getTermFrequencies();
System.out.println("FieldName:" + fieldName);
for (int j = 0; j < terms.length; j++)
{
System.out.println("[" + terms[j] + ":" + frequences[j] + "]");
}
System.out.println();
}
System.out.println();
}

你可能感兴趣的:(F#,Blog,Lucene,J#)