Generic placeholder image
闲敲代码、落灯花
What's past is prologue

联系邮箱:email@hezehua.net


联系QQ:1907330840

座右铭

保持热情,持续学习,每日精进

Elasticsearch 定制评分(自定义评分)

Elasticsearch 定制评分(自定义评分)

本文与作者在csdn上的博文【Elasticsearch 定制评分(自定义评分)
原力计划】
保持同步


Elasticsearch 的相似度算法被定义为检索词频率/反向文档频率, TF/IDF 。

一. 相关概念:

  1. 检索词频率:tf

词 t 在文档 d 的词频( tf )是该词在文档中出现次数的平方根。

tf(t in d) = √frequency

检索词在该字段出现的频率?出现频率越高,相关性也越高。 字段中出现过 5 次要比只出现过 1 次的相关性高。

  1. 反向文档频率:idf

词 t 的逆向文档频率( idf )是:索引中文档数量除以所有包含该词的文档数,然后求其对数。

idf(t) = 1 + log ( numDocs / (docFreq + 1))

每个检索词在索引中出现的频率?频率越高,相关性越低。检索词出现在多数文档中会比出现在少数文档中的权重更低。

二、计算公式为:

score(q,d)  =  queryNorm(q)  · coord(q,d)  · ∑ (tf(t,d) · idf(t)² · t.getBoost() · norm(t,d))  

其它参数定义:

  1. 字段长度准则:norm

字段长度归一值( norm )是字段中词数平方根的倒数。

norm(d) = 1 / √numTerms

字段的长度是多少?长度越长,相关性越低。 检索词出现在一个短的 title 要比同样的词出现在一个长的 content 字段权重更大。

  1. 查询归一因子

查询归一因子queryNorm )试图将查询 归一化 ,这样就能将两个不同的查询结果相比较。

这个因子是在查询过程的最前面计算的,具体的计算依赖于具体查询

queryNorm = 1 / √sumOfSquaredWeights 

sumOfSquaredWeights 是查询里每个词的 IDF 的平方和。

以上是对于一个词项检索时的相关度计算,当查询多个词项时,得出多个相关度,则需要按照向量空间模型来计算整体的相似度:

向量空间模型:vector

向量空间模型(vector space model) 提供一种比较多词查询的方式,单个评分代表文档与查询的匹配程度

在向量空间模型里,向量空间模型里的每个数字都代表一个词的 权重 ,与 词频/逆向文档频率(term frequency/inverse document frequency) 计算方式类似。

3、控制相关度

一般来说,控制相关度的需求,分为两种:

  1. 忽略TF/IDF
    即不需要评分,可以使用constant_score来达成,在 constant_score 查询中,它可以包含查询或过滤,为任意一个匹配的文档指定评分 1 ,忽略 TF/IDF 信息。

  2. 定制评分
    function_score 查询 是用来控制评分过程的终极武器,它允许为每个与主查询匹配的文档应用一个函数,以达到改变甚至完全替换原始查询评分 _score 的目的。本文主要介绍使用script_score函数。

使用脚本计算评
script_score
自定义脚本可以完全控制评分计算:

{
    "function_score": {
        "functions": {
            "script_score": {
                "script": "doc['price'].value + doc['margin'].value"
            }
        }
    }
}

4、Painless

es脚本引擎,简单安全,无痛使用,Painless使用白名单来限制函数与字段的访问,针对es的场景来进行优化,只做es数据的操作,更加轻量级。

Painless中变量可以声明为基本数据类型、引用类型、字符串、void(不返回值)、数组以及动态类型。其支持下面基本类型:

byte, short, char, int, long, float, double, boolean.声明变量与java类似:

int i = 0; double a; boolean g = true;

数组类型支持一维和多维,初始值为null。与引用类型一样,使用new关键字,并为每个维度设置中括号

int[] x = new int[2];  
x[0] = 3;  
x[1] = 4;  

int[] b = new int[] {1,2,3,4,5};  

painless支持动态类型,elasticsearch会自动推断类型

def a = 1;  
def b = "foo";  
def[][] h = new def[2][2];  

条件语句和运算符

Painless包含完整的操作符列表,除了它们的优先级和结合性之外,这些操作符与其他高级语言几乎兼容。

if (doc['foo'].value = 5) {  
    doc['foo'].value *= 10;
} 
else {  
    doc['foo'].value += 10;
}

Painless支持if else,但不支持else ifswitch

循环

def total = 0;  
for (def i = 0; i 

5、控制相关度实践

该实例中将使用script_score,将评分设置为:
doc['download_cnt'].value * 2.5 +doc['replication_cnt'].value * 1.2

{
    "query": {
        "function_score": {
            "query": {
                "match": {
                    "name": "1"
                }
            },
            "functions": [
                {
                    "script_score": {
                        "script": {
                            "params": {
                                "download_ratio": 2.5,
                                "replication_ratio": 1.2
                            },
                            "lang": "painless",
                            "inline": "doc['download_cnt'].value * params.download_ratio + doc['replication_cnt'].value * params.replication_ratio"
                        }
                    }
                }
            ]
        }
    }
}

_search操作中所有的返回值,都可以通过一个map类型变量doc获取。和所有其他脚本语言一样,用[]获取map中的值。这里要强调的是,doc只可以在_search中访问到

猜你喜欢
elasticsearch 去重计数
阅读 146

去重计数不是精确计数,数据量大的情况下会有误差,官方文档说的是,默认的情况下百万级数据会有5%的误差,实测如下: 实际文档数:1924920 去重计数:1912715 误差率:(1924920 - 1912715)/ 1924920 = 0.006 %0.6的误差率还能接受,如果需要更高的准确...

Elasticsearch 数据写入原理
阅读 167

1、elasticsearch 如何使文档可以被搜索 为了支持全文检索而采用倒排索引,倒排索引包含一个有序列表,列表包含所有文档出现过的词项 ,对于每一个词项,包含了它所有曾出现过文档的列表。 早期的倒排索引,会在文档变化时,重建新的索引,直到完成后替换掉旧的索引,这样新的变化就可以被搜索到。 倒...

Elasticsearch 模糊搜索
阅读 376

Es 实现类似于mysql的模糊搜索: 比如:对字段 keywords 进行 模糊搜索 带“愉”字的文档: { "query": { "bool": { "filter": [ { ...

记一次ElasticSearch 更改 mapping 字段类型的过程
阅读 736

首先,es不支持直接跟那个该mappinng,所以,更改 mapping 实质上是重建索引。 操作步骤如下: 1、为当前这个索引old_index设置一个别名my_index: curl -XPOST localhost:9200/_aliases -d ' { "act...

Elasticsearch 搜索数组字段
阅读 651

1、搜索 数组字段 tags 中同时存在元素 str_a、str_b{ "query": { "bool": { "filter": [ { "term":...

Elasticsearch实战:给博客打造全文检索
阅读 193

学习和使用Elasticsearch有一段时间了,项目中大量使用到了es,但对于我来说都是部分或者局部地去使用,所以得找个时间好好整理并且再完整时实践一下es,于是就有了这篇文章,本文将先简单介绍一下使用到的相关技术,然后再整体讲解实战内容。首先系统架构是LNMP,很简单的个人博客网站(逐步前...

elasticsearch查询文档数量
阅读 229

查询文档数量时很常见的操作,一般可以直接使用count获取文档数,但是获取到数量信息,在【分页】应用中,意味着需要查询分页然后再查询总数。 有另一种方法,可以让我们在一次查询中获取分页数据并得到总量。 在搜索时,结果中的 hits.total 信息中会包含一个整数值表示文档数,当实际文档数小于10...