Elasticsearch全文搜索与TF/IDF 原

转载: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

IT课店,发现好课程:https://www.itkedian.com 一个致力于快速发现大数据、人工智能、区块链等新技术课程的站点。

猜你喜欢

转载自blog.csdn.net/m0_37870649/article/details/81673215
今日推荐