转载:https://my.oschina.net/stanleysun/blog/1594220
一、TF/IDF
1. TF
TF:Term Frequency,即词频。它表示一个词在内容(如某文章)中出现的次数。为了消除文档本身大小的影响,通常,它的定义是:
TF = 某个词在文档中出现的次数 / 文档的总词数
也有其他表示方法,在Elasticsearch (lucene)中的使用的方法是
tf(t in d) = √frequency , 即 (某个词t在文档d中出现的次数) 的 平方跟
某个词出现越多,表示它约重要。比如某篇新闻中,“剑术”出现了5次,“电视”出现了1次,很可能这是一个剑术赛事报道。
如果这篇新闻中,“中国”和“剑术”出现的次数一样多,是不是表示两者同等重要呢?答案是否定的,因为中国这个词很常见,它难以表达文档的特性。而剑术很少见,更能表达文章的特性。
某个词越少见,就越能表达一篇文章的特性,反之则越不能。像“的”、“了”这些词,在所有文档中出现的频率都特别高,以至于失去了表达文章特性的意义。人们干脆称它们为“停用词”,直接从统计中忽略掉。
2. IDF
IDF(Inverse Document Frequency),即逆文档频率,它是一个表达词语重要性的指标。通常,它的计算方法是:
IDF=log(语料库中的文档数/(包含该词的文档数+1))
如果所有文章都包涵某个词,那个词的IDF=log(1)=0, 即重要性为零。停用词的IDF约等于0。
如果某个词只在很少的文章中出现,则IDF很大,其重要性也越高。
为了避免分母为0,所以+1.
在Elasticsearch (lucene)中的计算方法是
idf(t) = 1 + log ( numDocs / (docFreq + 1)) ,
即 1 + log ( 索引中的文档总数 / (包含该词的文档数 + 1))
上述公式是文档中给的,但实际中用的是 log(1 + (docCount - docFreq + 0.5) / (docFreq + 0.5))
TF-IDF值
TF-IDF = TF X IDF
在Elasticsearch中,还有一个概念叫 字段长度的归一化,Field-Length Norm.
字段内容越短,权重越大。如果一个关键词出现在较短的字段中,比如title,就比它出现在长字段(如简介)中更能表达文章的特性。
norm(d) = 1 / √numTerms 即: 1 / 词出现次数的平方根
二、elasticsearch的全文搜索
elasticsearh的全文搜索涉及到两个重要的方面:相关性(Relevance)和分析(Analysis)
相关性(Relevance)
它是评价查询与其结果间的相关程度,并根据这种相关程度对结果排名的一种能力,这种计算方式可以是 TF/IDF 方法(参见 相关性的介绍)、地理位置邻近、模糊相似,或其他的某些算法。本文只介绍TF/IDF方法。
TF/IDF 相关性方法分析
做一次搜索,带explain,elasticsearch会返回如何匹配。比如在title字段中进行全文搜索,关键词为'python'
GET course/_search?explain
{
"query": {
"multi_match" : {
"query": "python",
"fields": [ "title" ]
}
},"size":10
}
返回内容中,第一条匹配的结果如下
{
"_shard": "[course][0]",
...
"_score": 6.1884723,
"_source": {
"title": "Python 语句",
...
},
"_explanation": {
"value": 6.1884723,
"description": "weight(title:python in 1363) [PerFieldSimilarity], result of:",
"details": [
{
"value": 6.1884723,
"description": "score(doc=1363,freq=1.0 = termFreq=1.0\n), product of:",
"details": [
{
"value": 4.4812255,
"description": "idf, computed as log(1 + (docCount - docFreq + 0.5) / (docFreq + 0.5)) from:",
"details": [
{
"value": 17,
"description": "docFreq",
"details": []
},
{
"value": 1545,
"description": "docCount",
"details": []
}
]
},
{
"value": 1.3809776,
"description": "tfNorm, computed as (freq * (k1 + 1)) / (freq + k1 * (1 - b + b * fieldLength / avgFieldLength)) from:",
"details": [
{
"value": 1,
"description": "termFreq=1.0",
"details": []
},
{
"value": 1.2,
"description": "parameter k1",
"details": []
},
{
"value": 0.75,
"description": "parameter b",
"details": []
},
{
"value": 7.861489,
"description": "avgFieldLength",
"details": []
},
{
"value": 2.56,
"description": "fieldLength",
"details": []
}
]
}
]
}
]
}
}
解释
"value": 4.4812255,
"description": "idf, computed as log(1 + (docCount - docFreq + 0.5) / (docFreq + 0.5)) from:",
上面是求idf值的值。idf=ln(1 + (docCount - docFreq + 0.5) / (docFreq + 0.5))=ln(1+(1545-17+0.5)/(17+0.5)) = ln(88.34)=4.4812255
//返回内容里用了log(以10为底的对数), 实际是ln (以e为底的对数)
"value": 1.3809776,
"description": "tfNorm, computed as (freq * (k1 + 1)) / (freq + k1 * (1 - b + b * fieldLength / avgFieldLength)) from:",
上面是求tfNorm(归一化后的TF)的值。根据描述tfNorm = (freq * (k1 + 1)) / (freq + k1 * (1 - b + b * fieldLength / avgFieldLength))
其中termFreq=1,k1=1.2, b=0.75, avgFieldLength=7.861489, fieldLength=2.56。
为什么要用这样的公式,以及k1和b的值是怎么来的,我也不清楚。
计算最终结果,tfNorm=1.38.
"value": 6.1884723,
"description": "score(doc=1363,freq=1.0 = termFreq=1.0\n), product of:",
最终得分 TF-IDF = TF * IDF =4.4812255 * 1.3809776 = 6.1884723
---------------------------------------------------------------------
扩展阅读:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/17/2595249.html