什么是文档匹配度?
在ES中执行一个搜索请求在默认情况下搜索的结果集是按照匹配度倒序排列。但是什么是文档匹配度?它是如何被计算的呢?
每个文档的匹配度评分在es中被表示为一个浮点型的正数——“_score”,文档的_score评分越高,文档与搜索词的匹配度越大。
在查询中一个查询子句会为每一个文档生成一个_score,文档评分的计算依赖于具体查询子句的类型,不同的查询子句被用在不同的搜索场景中,比如:一个fuzzy查询的_score表示拼写所找到的关键词和原始搜索请求中的词的相似度,一个terms查询的_score表示我们查询的词在文档中所占的百分比。那么,我们通常所说的查询字符串与文档的匹配算法是什么呢?
在Elasticsearch中标准的相似度算法叫做 term freqyency/inverse document frequency(也叫做TF/IDF),该算法是在Lucene中实现,以下是Lucene计算文档评分的公式:
评分公式详解看这篇文章:http://www.hankcs.com/program/java/lucene-scoring-algorithm-explained.html
TF-IDF算法主要基于以下几个参数:
Term frequency(词频)
词频的含义是:词条在查询字段上出现的频率,出现的次数越多,相关度越大。比如,在文档A中的某个字段上一个词出现了5次比文档B中同一个字段同一个词出现1次的相关度要大
定义:词频(TF) = 某个词在某一文档中出现的次数
Inverse document frequency(逆文档频率)
逆文档频率的含义是:词条在整个索引上出现的频率,出现的次数越多,相关度越低,词条出现在更多的文档中那么该词条的权重将会更低(注:如果一个词在索引中存在于大多数的文档中说明该词是一个“公共词”,因此权重会更低)
定义:逆文档频率(IDF) = ln(numDocs / (docFreq + 1)) + 1,这里的ln表示以自然数e为底的对数函数,numDocs是索引中总文档数,docFreq是查询词所出现的文档数
Field-length norm(字段长度标准化)
字段长度标准化的含义是:表示字段所包含词条的数量,词条数数越多相关度越低。比如,同一个词出现在title中比出现在content中的相关度要大。
在单个查询中将会结合TF/IDF评分和其他一些因素来完成打分。比如在短语查询(query_phrase)中词的先后顺序,或者在fuzzy查询中搜索词和匹配词的相关度(编辑距离)
相关度不仅仅被用在全文检索中,还被用在 yes/no 查询中(如range,term查询等),更多的查询子句被匹配那么相关度评分_score越高。
当执行一个复杂的多子句查询时(比如bool查询),每个查询子句会计算出_score并最终被合并到全局的_score上。
在一个查询中我们可以使用explain参数来查看文档得分如何被计算出来的(这个参数会带来额外的性能开销,在生产环境必须禁止,该参数仅用于debug),看看下面的例子如使用该参数:
该查询执行的结果里会在每一个文档中都会嵌入一段用于表明该文档得分是如何被计算的Json,如: 上面的总得分0.076713204 = 1 * 0.30685282 * 0.25其中IDF(docFreq=1,maxDocs=1) = ln(1 / (1 + 1)) + 1 = 0.30685282 其中fieldNorm = lengthNorm = 1 / sqrt(1 + 3) = 0.25