Elasticsearch
的得分机制是一个基于词频和逆文档词频的公式,简称为
TF-IDF
公式,所以先来研究下
TF-IDF
原理。
1. TF-IDF原理
TF-IDF
的英文全称是:Term Frequency - Inverse Document Frequency
,中文名称词频-逆文档频率。
常用于文本挖掘,资讯检索等应用,在NLP
以及推荐等领域都是一个常用的指标,用于衡量字词的重要性。
比较直观的解释是,如果一个词本来出现的频率就很高,如the,那么它就几乎无法带给读者一些明确的信息。
一般地,以TF-IDF
衡量字词重要性时
- 某个字词在某个文档中出现的频率越高,那么该字词对该文档就有越大的重要性,它可能会是文章的关键词(词在单个文档中出现的频率,相对于当个文档!!!)
- 但若字词在词库中出现的频率越高,那么字词的重要性越低,如
the
。(相对于整个文档集合,也就是词库)
1.1 计算公式
TF-IDF
即是两者相乘,词频乘以逆文档频率,如下:
T
F
−
I
D
F
=
T
F
∗
I
D
F
TF-IDF=TF*IDF
TF−IDF=TF∗IDF
下标i
,j
的含义:编号为j
的文档中的词语i
在该文档中的词频,即所占比例,n
为该词语的数量。如下:
换言之,就是词语出现的次数与文档中所有词总数的比值。
T
F
i
j
=
n
i
j
n
∗
j
TF_{ij} = \frac{n_{ij}}{n_{*j}}
TFij=n∗jnijN
表示文档总数,Ni
表示文档集中包含了词语i的文档数。
对分子分母加一是为了避免某些词语没有在文档中出现过,导致分母为零的情况。
IDF
针对某个词计算了它的逆文档频率,即包含该词语的文档比例的倒数(再取对数),若IDF
值越小,分母越大,说明这个词语在文档集中比较常见不具有鲜明的信息代表性,TF-IDF
的值就小。
总之TF-IDF
的值,通常希望它越大越好,大值代表性强。如下:
I
D
F
i
=
l
o
g
(
N
+
1
N
i
+
1
)
IDF_i=log (\frac{N+1}{N_i+1})
IDFi=log(Ni+1N+1)
1.2 示例说明
有两个文档,即doc1
、doc2
,并去它们的并集
doc1 = "The cat sat on my bed"
doc2 = "The dog sat on my knees"
# 构建词库,union是并集操作
wordSet = set(doc1.split()).union(set(doc2.split()))
两个文档的并集如下:
{‘The’,‘bed’,‘cat’,‘dog’,‘knees’,‘my’,‘on’,‘sat’}
doc1
、doc2
两个文档对应的词在并集中的统计情况:
序号 | cat | sat | my | on | dog | bed | The | knees |
---|---|---|---|---|---|---|---|---|
0 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 0 |
1 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 1 |
1.2.1 计算TF
计算词频 TF
,对单个文档统计:
再理解一下,何为TF,表示单个单词占当前文档所有单词集合的比值。即1/6=0.16666666666…
cat | sat | my | on | dog | bed | The | knees |
---|---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 0 | 1 | 1 | 0 |
0.166666… | 0.166666… | 0.166666… | 0.166666… | 0 | 0.166666… | 0.166666… | 0 |
1.2.2 计算IDF
逆文档频率IDF
,全局只有一份逆文档频率,对所有文档统计
N
表示文档总数,
Ni`表示文档集中包含了词语i的文档数。此时N=2,共有两个文档。Ni表示含有单词的文档个数。
cat | sat | my | on | dog | bed | The | knees |
---|---|---|---|---|---|---|---|
0.17609125… | 0.0 | 0.0 | 0.0… | 0.17609125… | 0.17609125… | 0.0 | 0.17609125… |
1.2.3 TF-IDF计算
最终计算:TF-IDF = TF * IDF
序号 | cat | sat | my | on | dog | bed | The | knees |
---|---|---|---|---|---|---|---|---|
0 | 0.029349 | 0 | 0 | 0 | 0.029349 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 0.029349 | 0 | 0 | 0 | 0.029349 |
2. Elasticsearch打分机制
上面介绍了TF-IDF的原理,而ES的得分机制就是基于词频和逆文档词频的公式,即TF-IDF
公式。
s
c
o
r
e
(
q
,
d
)
=
c
o
o
r
d
(
q
,
d
)
⋅
q
u
e
r
y
N
o
r
m
(
q
)
⋅
∑
t
i
n
q
(
t
f
(
t
i
n
d
)
⋅
i
d
f
(
t
)
2
⋅
t
.
g
e
t
B
o
o
s
t
(
)
⋅
n
o
r
m
(
t
,
d
)
)
score(q,d) = coord(q,d)\cdot queryNorm(q)\cdot \sum_{t in q}(tf(t in d)\cdot idf(t){^2}\cdot t.getBoost()\cdot norm(t,d))
score(q,d)=coord(q,d)⋅queryNorm(q)⋅tinq∑(tf(tind)⋅idf(t)2⋅t.getBoost()⋅norm(t,d))
公式中将查询作为输入,使用不同的手段来确定每一篇文档的得分,将每一个因素最后通过公式综合起来,返回该文档的最终得分。这个综合考量的过程,在ES中这种相关性称为得分。
考虑到查询内容和文档的关系比较复杂,所以公式中需要输入的参数和条件非常得多,但是其中比较重要的其实是TF-IDF
算法 ,再次解释一下。
-
TF
(词频)
Term Frequency : 搜索文本中的各个词条在查询文本中出现了多少次,次数越多,就越相关,得分会比较高
-
IDF
(逆文档频率)
Inverse Document Frequency : 搜索文本中的各个词条在整个索引的所有文档中出现了多少次,出现的次数越多,说明越不重要,也就越不相关,得分就比较低。
2.1 示例说明
在查询语句的最后加上explain=true
,会把得分过程打印。
注:当前
ElasticSearch
的scorpios
索引里,只有一个文档。
# 创建索引
PUT /scorpios
# 增加文档数据,此时索引中只有这一条数据
PUT /scorpios/_doc/1
{
"text":"hello"
}
# 增加分析参数
GET /scoripos/_search?explain=true
{
"query": {
"match": {
"text": "hello"
}
}
}
执行后,会发现打分机制中有 2 个重要阶段:计算 TF
值和 IDF
值
最后的分数为:
2.2 计算 TF 值
f r e q / ( f r e q + k 1 ∗ ( 1 − b + b ∗ d l / a v g d l ) ) freq/(freq + k1 * (1-b+b*dl/avgdl)) freq/(freq+k1∗(1−b+b∗dl/avgdl))
参数 | 含义 | 取值 |
---|---|---|
freq | 文档中出现词条的次数 | 1.0 |
k1 | 术语饱和参数 | 1.2(默认值) |
b | 长度规格参数(单词长度对于整个文档的影响程度) | 0.75(默认值) |
dl | 当前文中分解的字段长度 | 1.0 |
avgdl | 查询文档中分解字段数量/查询文档数量 | 1.0 |
TF(词频) | 1.0/(1+1.2 * (1-0.75+0.75 * 1.0/1.0)) | 0.454545 |
2.3 计算 IDF 值
l o g ( 1 + ( N − n + 0.5 ) / ( n + 0.5 ) ) log(1+(N -n +0.5)/(n + 0.5)) log(1+(N−n+0.5)/(n+0.5))
参数 | 含义 | 取值 |
---|---|---|
N | 包含查询字段的文档总数(不一定包含查询词条) | 1 |
n | 包含查询词条的文档数 | 1 |
IDF(逆文档频率) | log(1+(1-1+0.5)/(1+0.5)) | 0.2875821 |
注:这里的 log 是底数为e 的对数
2.4 计算文档得分
b o o s t ∗ i d f ∗ t f boost * idf * tf boost∗idf∗tf
参数 | 含义 | 取值 |
---|---|---|
boost | 词条权重 | 2.2(基础值)*查询权重(1) |
idf | 逆文档频率 | 0.2876821 |
tf | 词频 | 0.454545 |
score(得分) | 2.20.28768210.454545 | 0.2876821 |
2.5 增加新的文档测试得分
- 增加一个毫无关系的文档
# 增加文档
PUT /scorpios/_doc/2
{
"text" : "spark"
}
# 得分:0.6931741
GET /scorpios/_search
{
"query": {
"match": {
"text": "hello"
}
}
}
因为新文档无词条相关信息,所以匹配的文档数据得分就应该较高
- 增加一个一模一样的文档
# 增加文档
PUT /scorpios/_doc/2
{
"text" : "hello"
}
# 得分:0.18232156
GET /scorpios/_search
{
"query": {
"match": {
"text": "hello"
}
}
}
因为新文档含词条相关信息,且多个文件含有词条,所以显得不是很重要,得分会变低
- 增加一个含有词条,但是内容较多的文档
# 增加文档
PUT /scorpios/_doc/2
{
"text" : "hello elasticsearch"
}
# 得分:0.14874382
GET /scorpios/_search
{
"query": {
"match": {
"text": "hello"
}
}
}
因为新文档含词条相关信息,但只是其中一部分,所以查询文档的分数会变得更低一些。
3. 案列
3.1 需求
查询文档标题中含有Hadoop
,Elasticsearch
,Spark
的内容,优先选择Spark
的内容
3.2 准备数据
# 创建索引
PUT /test
# 准备数据
PUT /test/_doc/1001
{
"title" : "Hadoop is a Framework",
"content" : "Hadoop 是一个大数据基础框架"
}
PUT /test/_doc/1002
{
"title" : "Hive is a SQL Tools",
"content" : "Hive 是一个 SQL 工具"
}
PUT /test/_doc/1003
{
"title" : "Spark is a Framework",
"content" : "Spark 是一个分布式计算引擎"
}
3.3 查询数据
# 查询文档标题中含有“Hadoop”,“Elasticsearch”,“Spark”的内容
GET /test/_search?explain=true
{
"query": {
"bool": {
"should": [
{
"match": {
"title": {
"query": "Hadoop", "boost": 1
}
}
},
{
"match": {
"title": {
"query": "Hive", "boost": 1
}
}
},
{
"match": {
"title": {
"query": "Spark", "boost": 1
}
}
}
]
}
}
}
此时会发现,Spark
的结果并不会放置在最前面
此时可以更改 Spark
查询的权重参数 boost
,看看查询的结果有什么不同文章来源:https://www.toymoban.com/news/detail-424411.html
# 查询文档标题中含有“Hadoop”,“Elasticsearch”,“Spark”的内容
GET /test/_search?explain=true
{
"query": {
"bool": {
"should": [
{
"match": {
"title": {
"query": "Hadoop", "boost": 1
}
}
},
{
"match": {
"title": {
"query": "Hive", "boost": 1
}
}
},
{
"match": {
"title": {
"query": "Spark", "boost": 2
}
}
}
]
}
}
}
文章来源地址https://www.toymoban.com/news/detail-424411.html
到了这里,关于ElasticSearch之score打分机制原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!