Solr全文检索基本原理及评分机制

Posted ChangbaDev

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Solr全文检索基本原理及评分机制相关的知识,希望对你有一定的参考价值。

Solr是一个高性能,采用Java5开发,基于Lucene的全文搜索服务器。同时对其进行了扩展,提供了比 Lucene更为丰富的查询语言,同时实现了可配置、可扩展并对查询性能进⾏了优化,并且提供了一个完善的功能管理界面,是一款⾮常优秀的全文搜索引擎。(来⾃百度百科) 这里主要介绍:

  • 全⽂检索基本原理

  • 评分机制

全文检索基本原理

Solr/Lucene采用的是一种反向索引(倒排索引) 下图是个很好的说明:

  • 左边保存的是字符串序列,称之为字典

  • 右边是字符串的文档(Document)编号链表,称为倒排表(Posting List)

譬如搜索”爱“,索引会找到,包含“爱”的文档有35,56,255,267,355,而不用在整个数据中去搜索了,如果我们搜索即有“爱”,又有“我”,那么取两个倒排表的交集即可(结果56,267)。

索引创建

索引的创建过程如下:
这里大致讲解一下数据录入到Solr中都发生了什么,创建的过程大致如下:

Solr全文检索基本原理及评分机制

现在举个例子来讲解下
比如现在有以下两句歌词:

  • 月亮代表我的心

  • 借我借我一双慧眼吧

第一步:把原始文档交给分词组件(Tokenizer) 分词组件(Tokenizer)会做以下几个事情(这个过程称为: Tokenize),处理得到的结果是词汇单元(Token):(譬如我们整合分词组件是IK分词器)

  1. 将文档分成⼀个单独的单词(如果有分词器,则会按照分词器来进⾏分词)

  2. 去除标点符号

  3. 去除停止词(stop word)

第二步:词汇单元(Token)传给语言处理理组件(Linguistic Processor) 语⾔处理组件(linguistic processor)主要是 对得到的词元(Token)做一些语言相关的处理(英文的处理如:⼤小写转换,将单词缩转变或减为词根形式)。 语⾔处理组件(linguistic processor)处理得到的结果称为词(Term),例子中经过语言处理后得到的词(Term)如下:
月亮 代表 我 心 借我 我 借我 我 一双 一 双 慧眼 

第三步:得到的词(Term)传递给索引组件(Indexer) 

1.利用得到的词(Term)创建一个字典 

Solr全文检索基本原理及评分机制


2.对字典按字母顺序排序 

Solr全文检索基本原理及评分机制


3.合并相同的词(Term)成为文档倒排(Posting List)链表 


以上就是有关Solr索引的简介了,下面来说比较重要的Solr的打分规则,这里有两个重要的词 

  1. Document Frequency(df):⽂档频次,表示多少文档出现过此词(Term)

  2. Term Frequency(tf):词频,表示某个文档中该词(Term)出现过⼏次

评分机制分析

评分机制的大致准则有两个:

  • 整个文档集合中包含某个词的文档数量越少,这个词越重要(IDF)

  • 某个词或短语在一篇文章中出现的次数越多,越相关(TF)

下面譬如在我们唱吧中搜索(告白气球),用querydebug取一条数据来分析(q:告白气球&&qf:name): 

总打分计算

可见最后的得的总分是由在name域中搜索到的“告白”和“气球“得的分加上一个权重分
即:域的得分7.120619=3.3469656 + 3.773653 权重的分=0.30002856
总分 7.4206476 = 7.120619+0.30002856

每个域打分规则

field的score得分=域权重fieldWeight * 查询权重queryWeight
3.3469656 = 0.6829876 * 4.900478 
3.773653 = 0.72521734 * 5.203479

queryWeight的计算

public void normalize(float queryNorm, float boost) {
            this.boost = boost;
            this.queryNorm = queryNorm;
            this.queryWeight = queryNorm * boost * this.idf.getValue();
            this.value = this.queryWeight * this.idf.getValue();
}

可以看出:
queryWeight = queryNorm * boost * idf ,而Lucene中boost默认为1
0.6829876 = 7.8407645 * 1 * 0.08710727
idf的计算
idf是项目在倒排文档中出现的频率,计算方式为

public float idf(long docFreq, long numDocs) {
        return (float)(Math.log((double)numDocs / (double)(docFreq + 1L)) + 1.0D);
}

其中Math.log(number)这个方法相当于数学的ln(number)

其实就是:1 +ln(文档总数/(包含t的文档数+1))
idf(7.8407645)=1+ln(3145090/(3362+1))
这就是为什么计算方式是物以稀为贵的准则了(出现关键词t的结果d越少,结果率反比越高。)
docFreq是根据指定关键字进行检索,检索到的Document的数量,我们测试的docFreq=3362;
numDocs是指索引文件中总共的Document的数量,我们测试的numDocs=3145090 queryNorm的计算

public float queryNorm(float sumOfSquaredWeights) {
        return (float)(1.0D / Math.sqrt((double)sumOfSquaredWeights));
}

Math.sqrt(number)这个方法相当于数学的√number 这里,sumOfSquaredWeights的计算是在org.apache.lucene.search.TermQuery.TermWeight类中的sumOfSquaredWeights方法实现:

public float sumOfSquaredWeights() {
      queryWeight = idf * getBoost(); // compute query weight   
      return queryWeight * queryWeight; // square it        
}     

其实默认情况下,sumOfSquaredWeights = idf * idf,因为Lucune中默认的boost = 1.0。

由此算出:

sumOfSquaredWeights=7.8407645 * 7.8407645 + 8.325566 * 8.325566 = 130.792637

queryNorm = 1/√130.792637 = 0.08710727

fieldWeight的计算

fieldWeight = tf * idf * fieldNorm 

简单说下tf的计算 tf就是只term frequency 其实就是结果中term出现的次数
tf=√1 (如果结果是“告白告白气球”,那针对“告白”的tf=√2) 

fieldNorm的计算是在索引的时候确定了。如果使用ClassicSimilarity的话,它实际上就是lengthNorm,域越长的话Norm越小,在org/apache/lucene/search/similarities/ClassicSimilarity.java里面有关于它的计算:

public float lengthNorm(FieldInvertState state) {
    int numTerms;   
    if(this.discountOverlaps) {
       numTerms = state.getLength() - state.getNumOverlap();
   } else {
        numTerms = state.getLength();
   }
   return state.getBoost() * (float)(1.0D /Math.sqrt((double)numTerms));
}

fieldnorm(t,d)=d.getBoost() * lengthNorm(field) * f.getBoost()
lucene中getBoost默认都是1(和搜索时设置的权重有关),所以关键是lengthNorm(field),它的计算是1/sqrt(numTerms), 其中numTerms 表示的是分词的数量(如:告白气球分词为“告白”,“气球”,所以numTerms=2) 在实际中会发现计算出来的fieldNorm会和实际的结果有偏差,这里就不详细解释了,有兴趣可以参考下这篇文章

关于最后一项得分

其实就是bf参数,用函数来计算某个字段的权重,使用用户设置的公式来对文档的score进行计算。

到此为止,有关Solr的评分机制就已经介绍完了。


以上是关于Solr全文检索基本原理及评分机制的主要内容,如果未能解决你的问题,请参考以下文章

[摘]全文检索引擎Solr系列—–全文检索基本原理

Solr简介和使用(二期)

solr索引基本原理

solr索引基本原理

lucene搜索引擎的使用及原理分析

了解Solr6.1结构及实现原理