ElasticSearch 查询开销
ElasticSearch 在查询一个文档的时候,默认会根据倒排索引词项的匹配程度来做一个相关性的算分,每个文档都会做这个分析过程,如果文档数很庞大,这个过程其实是非常消耗性能的,那么是不是有什么办法可以取消掉这个算法过程
Constant Score
ElasticSearch 提供了一个查询的 API : Constant Score
利用这个API 可以忽略掉算分过程。它的原理是将查询转换成为一个filter 过滤,filter 查询是会走缓存的,所以性能提升是相当高的,毕竟省去了 随机IO 的操作。
- 将 QUERY 转化成为 Filter ,忽略 TF-IDF 相关性算分,避免相关性算分的性能开销
- Filter 会走缓存,可以有效利用缓存
POST movies/_search
{
"explain": true,
"query": {
"constant_score": {
"filter": {
"term": {
"title": "story"
}
}
}
}
}
如上就是一个Constant Score 的使用示例,我们可以看到结果,在 explain 中是没有算分的相关操作的,并且 socre 为默认值1
所以利用 Constant Score 可以忽略掉算分这个操作,一般是推荐这样使用的。
explain 可以查看 ElasticSearch是如何进行算分的
ElasicSearch 算分规则
相关性算分
要想了解 ElasticSearch 为什么要进行算分,我们得先知道什么叫做相关性。相关性,就是描述一个文档与查询语句的匹配程序,比如 一个文档是 “我爱中国” 与 “我是中国人” ,那么针对你的搜索语句 “爱中国”,相关性最高的文档是 “我爱中国”这一篇。
理解了相关性的概念之后,那么ElasticSearch 是如果表示相关性的,那便是通过一个分数来展示,相关性算分算出的分数越高证明相关性越高,那么这个文档就是你所要的。
- 相关性算分,描述一个文档与查询语句的匹配程度,打分的本质为了排序,将相关性高的文档排列在前
- es 5 之前,算分算法是 TF-IDF,es 5 之后为 BM 25
TF-IDF 算法
TF term frequency 词频
TF 是 term frequency 的缩写,表示检索词在一篇文档中出现的频率,也就是词频。
- 词频的计算规则是 检索词出现的次数除以文档的总数。
比如:有一篇文档 “我是中国人,我爱中国”,检索词是 “中国”,那么计算检索词的词频 就是 4 / 9 - TF 的相关性算分统计,将检索词在一篇文档中词频累加。
比如:检索词 “我 中国” ,相关性算分就是 TF(我) + TF(中国)
IDF 逆文档频率
- DF Document frequency 的缩写,Df 的概念是检索词在所有文档中出现的次数
- IDF inverse Document frequency 的缩写,倒转文档频率,算法是 log(全部的文档数 / 检索词出现过的文档数)
比如:现有 10 个文档,中国这个检索词在十个文档中都出现了,那么 IDF 就是 log(1)
TF-IDF
TF-IDF,其实就是将二者相乘各取每个检索词的加权和。
TF-IDF的主要思想是:如果某个单词在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。
TF(我)*IDF(我) + TF(我)*IDF(中国)
看这个图吧,我们主要看Lucene 的score 算法规则,发现影响这个因素的 有三个要点:
- TF
- IDF
- boosting (查询中可以设置这个值提升权重)
- field-length norm 字段长度归一值
BM 25
BM 25 其实是 TF-IDF 算法的一个改善,主要是解决 当词频太大的时候会得到一个稳定值的现象。
可以看到当词频达到一定数量的时候,两个算法的结果是有很大的区别的。
BM 25 提供了控制干预算分的两个参数设置。
- k1
这个参数控制着词频结果在词频饱和度中的上升速度。默认值为 1.2 。值越小饱和度变化越快,值越大饱和度变化越慢。 - b
这个参数控制着字段长归一值所起的作用, 0.0 会禁用归一化, 1.0 会启用完全归一化。默认值为 0.75 。
POST /testscore/_search
{
"explain": true,
"query": {
"match": {
"content": "elasticsearch"
}
}
}
我们可以看到分别对 boost、idf、tf 进行了计算,最终算分结果是 0.8713851
Boosting
ElasticSearch 提供了一些操作来影响这个算分过程,比如boosting API。
- positive 这个查询匹配的词项对算分有正面影响
- negative 这个查询匹配的词项对算分是负面影响
POST testscore/_search
{
"query": {
"boosting" : {
"positive" : {
"term" : {
"content" : "elasticsearch"
}
},
"negative" : {
"term" : {
"content" : "like"
}
},
"negative_boost" : 0.2
}
}
}
Boosting 其实是一种提升算法,是一种可以用来减小监督式学习中偏差的机器学习算法。