Lucene.Net笔记--逆向文档频率(IDF)
本博文通过分析Lucene代码,阐述了其计算逆向文档频率的完整过程。
先上 评分公式 如下:
Σt int q(tf(t in d) × idf(t)2 × boost(t.field in d) × lengthNorm(t.field in d)) × coord(q, d) × queryNorm(q)
逆向文档频率(IDF)
定义:逆向文件频率,指定的项(Term)在整个倒排索引中出现的频率。
在Lucene.Net.Search
名称空间下的Weight.GetSumOfSquaredWeights()
方法用来计算逆向文件频率。对于最简单的搜索(TermQuery
),它在Lucene.Net.Search.TermQuery.TermWeight
类中实现:
public override float GetSumOfSquaredWeights()
{
var idf = this.TermQuery
.GetSimilarity(this.Searcher)
.IdfExplain(this.TermQuery.Term, this.Searcher)
.Idf;
var queryWeight = idf*this.TermQuery.Boost; // Boost是在创建TermQuery时,由客户程序(如用户)传入的。
return queryWeight*queryWeight; // square it
}
Lucene.Net.Search.Weight
类是Lucene.Net.SearchQuery
类的包装类,其派生类的构造函数一般为
public DerivedWeight(DerivedQuery enclosingInstance, Searcher searcher)
{
}
Weight
类型总是包含对应的Query
及Searcher
的相关引用。
TermQuery.GetSimilarity(this.Searcher)
返回一个“相似度模型”,如果该方法的参数为一个Lucene.Net.Searcher.IndexSearcher
,而非Lucene.Net.Searcher.MultiSearcher
(多索引搜索),则返回的Similarity其实是一个默认实现:Lucene.Net.Search.DefaultSimilarity
,Similarity
及其派生类是评分公式和核心实现类。
考虑一般情况,上述代码中的Similarity.IdfExplain(Term, Searcher).Idf
实际上是用默认的评分公式(DefaultSimilarity实现)来计算某次搜索中的某个项的逆向文档频率。IdfExplain
方法返回一个Lucene.Net.Search.Explanation.IDFExplanation
抽象类,该抽象类主要用于生成评分注释,对于Idf值本身来说,该类仅起了一个Idf
参数传递作用。该抽象类没有任何成员上的实现,
using system;
namespace Lucene.Net.Search;
public class Explanation
{
public abstract class IDFExplanation
{
public abstract float Idf{get;}
public abstract string Explan();
}
}
在Lucene.net中的仅有的两个实现是Lucene.Net.Search.Similarity.AnonymousClassIDFExplanation1
和Lucene.Net.Search.Similarity.AnonymousClassIDFExplanation3
,分别用于“TermQuery”和“PhraseQuery”。下面来看一下Similarity.IdfExplain(Term, Searcher)
的具体实现
public virtual IDFExplanation IdfExplain(Term term, Searcher searcher)
{
int df = searcher.DocFreq(term); //计算有多少文档包含了参数中的Term
int max = searcher.MaxDoc; //整个索引中文档的总数
float idf = (float) (System.Math.Log(max / (double) (df + 1)) + 1.0);
return new AnonymousClassIDFExplanation1(df, max, idf2, this);
}
以上就是逆向文档频率的完整计算过程。将计算过程写入一个函数,如下所示:
using system;
using Lucene.Net.Search;
public override float GetSumOfSquaredWeights()
{
int df = this.Searcher.DocFreq(this.TermQuery.Term);//计算有多少文档包含了当前的Term
int totalDocNum = this.Searcher.maxDoc;//整个索引中文档的总数。
float idf = (float) (Math.Log(totalDocNum / (double) (df + 1)) + 1.0);
var queryWeight = idf*this.TermQuery.Boost; //Boost是在创建TermQuery时,由客户程序(如用户)传入的。
return queryWeight*queryWeight;
}