Elasticsearch 查询之Function Score Query

前言

ES 的主查询评分模式分为两种,是信息检索领域的重要算法: TF-IDF 算法 和 BM25 算法。

Elasticsearch 从版本 5.0 开始引入了 BM25 算法作为默认的文档评分(relevance scoring)算法。在此之前,Elasticsearch 使用的是 TF-IDF 算法作为默认的文档评分算法。从版本 5.0 起,BM25 算法取代了 TF-IDF,成为了默认的算法,用于计算文档与查询之间的相关性得分。

这个变化主要是为了更好地适应现代信息检索需求,BM25 算法在一些情况下能够提供更准确的文档排序和检索结果。

而 Function Score Query 不夸张的说是 ES 里面终极自定义打分的大招,非常的灵活并且功能强大,常规情况下,我们排序都是基于 _score 的,如果 _score相等的情况下,我们还可以额外增加排序字段,比如按日期,数量,价格等,但在搜索引擎中,排序往往并不像 SQL 那样,从左到右规整的按照多字段排序,在 SQL 里面,排序的主顺序一定是由左边的第一个字段决定的,但在搜索引擎种,却不仅仅是这样的,还可以通过 function score 做到那个字段贡献的分值大,排序顺序就以谁为主,因为这些是真实存在的需求场景,如下:

  • 新闻场景:搜索具有某个关键词的文档,同时结合文档的时效性进行综合排序
  • 导航场景:搜索某个地点附近的饭店,同时根据距离远近和价格等因素综合排序
  • 论坛场景:搜索包含某个关键词的文章,同时根据浏览次数和点赞数进行综合排序

SQL 的排序模型

select * from table order by A, B, C

搜索引擎的排序模型

query * from index oder by score max(A, B, C)

写入数据

为了用实际例子讲解 function score,我们先写入几条数据

POST test01/doc/_bulk
{ "index" : { "_id" : "1" } }
{"title": "kubernetes", "content": "Development History","vote": 3,"year": 2015}
{ "index" : { "_id" : "2" } }
{"title": "kubernetes", "content": "Competitive Analysis","vote": 5,"year": 2018}
{ "index" : { "_id" : "3" } }
{"title": "kubernetes docker","content": "The connection between virtual and docker technology","vote": 100,"year": 2011}
{ "index" : { "_id" : "4" } }
{"title": "kubernetes network","content": "router vlan tcp","vote": 20,"year": 2009}

查询数据

查询关键词:kubernetes

GET test01/_search?search_type=dfs_query_then_fetch
{"query": {"bool": {"should": [{"term": {"title": "kubernetes"}}]}},"explain": false
}

返回结果:

    "hits" : [{"_index" : "test01","_type" : "doc","_id" : "2","_score" : 0.12776,"_source" : {"title" : "kubernetes","content" : "Competitive Analysis","vote" : 5,"year" : 2018}},{"_index" : "test01","_type" : "doc","_id" : "1","_score" : 0.12776,"_source" : {"title" : "kubernetes","content" : "Development History","vote" : 3,"year" : 2015}},{"_index" : "test01","_type" : "doc","_id" : "4","_score" : 0.09954306,"_source" : {"title" : "kubernetes network","content" : "router vlan tcp","vote" : 20,"year" : 2009}},{"_index" : "test01","_type" : "doc","_id" : "3","_score" : 0.081535265,"_source" : {"title" : "kubernetes mesos swarm","content" : "The connection between virtual and docker technology","vote" : 100,"year" : 2011}}]

结果看起来是正常的,ok,现在我们要改变需求了,加入了基于点赞量的加权,也就是说匹配关键词并且点赞量高的优先展示,因为点赞量高意味着这些文章质量更高,所以需要优先曝光,这个时候我们就需要用到 function score

Function Score Query介绍

计算原理

使用主查询 的 TF-IDF 或者 BM25 算法得出来的默认评分简称为: query_score

使用 Function Score 查询结合自定义策略得出来的评分简称为:function_score

最终用于排序的评分称为 sort_score

在使用了 自定义的 Fuction Score 之后,我们最终得出来的 sort_score 就是使用 query_score 和 function_score以某种运算形式 (score_mode) 计算出来的,这个策略默认是相乘,也即:

sort_score = query_score * function_score

function_score内的score_mode

score_mode有六种:

mode

描述

multiply

多个函数 score 相乘(默认)

sum

多个函数 score 求和

avg

多个函数 score 取平均值

first

使用第一个 filter 函数的 score

max

取多个函数 score 中最大的那个

min

取多个函数 score 中最大的那个

sort_score运算策略

sort_score 是 query_score 和 function_score以某种形式运算而来,支持的运算操作也有六种:

mode

描述

multiply

sort_score = query_score * function_score(默认)

sum

sort_score = query_score + function_score

avg

sort_score = avg ( query_score + function_score ) / 2

replace

sort_score = function_score

max

sort_score = max ( query_score + function_score )

min

sort_score = min ( query_score + function_score )

默认情况下,修改分数不会更改匹配的文档。要排除不满足特定分数阈值的文档,可以将 min_score 参数设置为所需的分数阈值

fuction score的评分函数
script_score

script_score 支持自定义脚本打分,也就是说可以用类编程语言的脚本来嵌入的打分逻辑,ES 之前用的是 groovy脚本因安全性有问题,现在换成了 Painless 脚本,详细可参考:Painless scripting language | Elasticsearch Guide [8.9] | Elastic

现在我们用 script_score 来完成上面查询场景中的,给点赞量的加权:

GET test01/_search?search_type=dfs_query_then_fetch
{"query": {"function_score": {"query": {"match": { "title": "kubernetes" }},"script_score": {"script": {"params": {"baseScore": 1},"source": "params.baseScore + doc['vote'].value"}},"boost_mode": "replace","score_mode": "multiply"}},"explain": false
}

结果如下:

    "hits" : [{"_index" : "test01","_type" : "doc","_id" : "3","_score" : 101.0,"_source" : {"title" : "kubernetes mesos swarm","content" : "The connection between virtual and docker technology","vote" : 100,"year" : 2011}},{"_index" : "test01","_type" : "doc","_id" : "4","_score" : 21.0,"_source" : {"title" : "kubernetes network","content" : "router vlan tcp","vote" : 20,"year" : 2009}},{"_index" : "test01","_type" : "doc","_id" : "2","_score" : 6.0,"_source" : {"title" : "kubernetes","content" : "Competitive Analysis","vote" : 5,"year" : 2018}},{"_index" : "test01","_type" : "doc","_id" : "1","_score" : 4.0,"_source" : {"title" : "kubernetes","content" : "Development History","vote" : 3,"year" : 2015}}]

在这个函数查询中,我们使用了 replace 策略,来直接使用 fuction_score的分数,注意 从 docValue 里面取出来的字段必须是number 类型才可以

weight

直接对查询加权:

例子一:

GET test01/_search?search_type=dfs_query_then_fetch
{"query": {"function_score": {"query": {"match": { "title": "kubernetes" }},"weight": 10}},"explain": false
}

结果:

    "hits" : [{"_index" : "test01","_type" : "doc","_id" : "2","_score" : 1.2775999,"_source" : {"title" : "kubernetes","content" : "Competitive Analysis","vote" : 5,"year" : 2018}},{"_index" : "test01","_type" : "doc","_id" : "1","_score" : 1.2775999,"_source" : {"title" : "kubernetes","content" : "Development History","vote" : 3,"year" : 2015}},{"_index" : "test01","_type" : "doc","_id" : "4","_score" : 0.9954306,"_source" : {"title" : "kubernetes network","content" : "router vlan tcp","vote" : 20,"year" : 2009}},{"_index" : "test01","_type" : "doc","_id" : "3","_score" : 0.8153527,"_source" : {"title" : "kubernetes mesos swarm","content" : "The connection between virtual and docker technology","vote" : 100,"year" : 2011}}]

例子二:

GET test01/_search?search_type=dfs_query_then_fetch
{"query": {"function_score": {"query": {"match_all": {}},"functions": [{"filter": { "match": { "content": "kubernetes" } },"weight": 1},{"filter": { "match": { "title": "mesos" } },"weight": 10},{"filter": { "match": { "content": "tcp" } },"weight": 20}]}},"explain": false
}

结果如下:

    "hits" : [{"_index" : "test01","_type" : "doc","_id" : "4","_score" : 20.0,"_source" : {"title" : "kubernetes network","content" : "router vlan tcp","vote" : 20,"year" : 2009}},{"_index" : "test01","_type" : "doc","_id" : "3","_score" : 10.0,"_source" : {"title" : "kubernetes mesos swarm","content" : "The connection between virtual and docker technology","vote" : 100,"year" : 2011}},{"_index" : "test01","_type" : "doc","_id" : "2","_score" : 1.0,"_source" : {"title" : "kubernetes","content" : "Competitive Analysis","vote" : 5,"year" : 2018}},{"_index" : "test01","_type" : "doc","_id" : "1","_score" : 1.0,"_source" : {"title" : "kubernetes","content" : "Development History","vote" : 3,"year" : 2015}}]

这个 filter 很适合竞价排名

random_score

random score 相当于把返回文档的顺序给打乱,比较适合随机召回文档

GET test01/_search?search_type=dfs_query_then_fetch
{"query": {"function_score": {"query": {"match_all": {}},"random_score": {}}},"explain": false
}

默认情况下,是每次查询的值都是随机的,但有时候我们想用同一个 id 的保持不变,不同 id 的结果随机,这个时候可以使用 seed 和 field 来控制:


GET test01/_search?search_type=dfs_query_then_fetch
{"query": {"function_score": {"query": {"match_all": {}},"random_score": {"seed": 10,"field": "_seq_no"}}},"explain": false
}

这个时候 seed 的值,就可以等同于 id,id 值一样的结果不变

field_value_factor
GET test01/_search?search_type=dfs_query_then_fetch
{"query": {"function_score": {"query": {"match": {"title":"kubernetes"}},"field_value_factor": {"field": "vote","factor": 1.2,"modifier": "sqrt","missing": 1},"boost_mode": "max"}},"explain": false
}

等价于script score 脚本 sqrt(1.2 * doc['vote'].value)

其中field 是文档种的字段,missing 是缺失值,factor 是放大的比值默认是 1,modifier 是对结果的再次处理,支持多种函数如:none, log, log1p, log2p, ln, ln1p, ln2p, square, sqrt, or reciprocal

decay functions

衰减函数

  • 以某个数值作为中心点,距离多少的范围之外逐渐衰减(缩小分数)
  • 以某个日期作为中心点,距离多久的范围之外逐渐衰减(缩小分数)
  • 以某个地理位置点作为中心点,方圆多少距离之外逐渐衰减(缩小分数)

一个例子:

"DECAY_FUNCTION": { "FIELD_NAME": { "origin": "11, 12","scale": "2km","offset": "0km","decay": 0.33}
}

上例的意思就是在距中心点方圆 2 公里之外,分数减少到三分之一(乘以 decay 的值 0.33)

DECAY_FUNCTION 可以是以下任意一种函数:

linear : 线性衰减函数
exp : 指数衰减函数
gauss : 高斯正常衰减函数

origin :

用于计算距离的原点。对于数字字段,必须以数字形式给出;对于日期字段,必须以日期形式给出;对于地理字段,必须以地理点形式给出。地理和数字字段是必需的。对于日期字段,默认值为现在。 origin 支持日期数学(例如 now-1h)

scale :

定义计算得分等于衰减参数时距原点 + 偏移量的距离。对于地理字段:可以定义为数字+单位(1km、12m、...)。默认单位是米。对于日期字段:可以定义为数字+单位(“1h”、“10d”、...)。默认单位是毫秒。对于数字字段:任何数字

offset :

如果定义了偏移量,则衰减函数将仅计算距离大于定义的偏移量的文档的衰减函数。默认值为 0

decay :

衰减参数定义如何在给定比例的距离上对文档进行评分。如果未定义衰减,则距离尺度上的文档将评分为 0.5

例如,现在新数据,标题匹配 kubernetes 后,按照优先检索位于 2011-2015 年份进行加权,不再按照点赞量:

GET test01/_search?search_type=dfs_query_then_fetch
{"query": {"function_score": {"query": {"match": {"title":"kubernetes"}},"gauss": {"year": {"origin": "2013", "offset": "2","scale": "2","decay": 0.1            }},"boost_mode": "max"}},"explain": false
}

解释一下:

上面使用高斯函数作为衰减,使用的是年份字段:

orgin:代表中心点是 2013 年

offset:2 代表 [2011, 2015] 作为中心圆,也就是 [2011, 2015]位于这之间的文档评分直接为 1

scala: 2 代表 [2009, 2017]之外的评分为 0.1

其他的,如果位于 2009-2011 范围的以及 2015-2017 范围的,就按正常评分就好了

结果如下:

    "hits" : [{"_index" : "test01","_type" : "doc","_id" : "3","_score" : 1.0,"_source" : {"title" : "kubernetes mesos swarm","content" : "The connection between virtual and docker technology","vote" : 100,"year" : 2011}},{"_index" : "test01","_type" : "doc","_id" : "1","_score" : 1.0,"_source" : {"title" : "kubernetes","content" : "Development History","vote" : 3,"year" : 2015}},{"_index" : "test01","_type" : "doc","_id" : "2","_score" : 0.12776,"_source" : {"title" : "kubernetes","content" : "Competitive Analysis","vote" : 5,"year" : 2018}},{"_index" : "test01","_type" : "doc","_id" : "4","_score" : 0.1,"_source" : {"title" : "kubernetes network","content" : "router vlan tcp","vote" : 20,"year" : 2009}}]

三种衰减的函数的曲线如下:

此外,如果用于计算衰减的字段包含多个值,则默认情况下会选择最接近中心点的值来确定距离。这可以通过设置 multi_value_mode 来更改:

min:距离是最小距离

max:距离是最大距离

avg:距离是平均距离

sum:距离是所有距离的总和

    "DECAY_FUNCTION": {"FIELD_NAME": {"origin": ...,"scale": ...},"multi_value_mode": "avg"}

function score 的其他参数

max_boost: 最大权重值的范围

boost_mode: 最终 query_score 和 function_score的计算策略

min_score: 最终的结果过滤掉评分低于这个值的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/100358.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

uniapp 顶部头部样式

<u-navbartitle"商城":safeAreaInsetTop"true"><view slot"left"><image src"/static/logo.png" mode"" class"u-w-50 u-h-50"></image></view></u-navbar>

Certify The Web (IIS)

一、简介 Certify The Web 适用于 Windows的SSL 证书管理器用户界面&#xff0c;与所有 ACME v2 CA 兼容&#xff0c;为您的 IIS/Windows 服务器轻松地安装和自动更新来自 Letencrypt.org 和其他 ACME 证书授权机构的免费 SSL/TLS 证书&#xff0c;设置 https 从未如此简单。 …

【中危】PowerJob 未授权访问漏洞 (CVE-2023-36106)

漏洞描述 PowerJob 是一款开源的分布式任务调度框架。 在 PowerJob 受影响版本中存在错误的访问控制漏洞。由于没有对/container/list接口做鉴权&#xff0c;未授权的攻击者可以构造 appId 参数访问 /container/list接口获取应用容器的标识、运行状态、日志等敏感信息。 漏洞…

java+springboot+mysql小区自来水实时监控管理系统

项目介绍&#xff1a; 使用javaspringbootmysql开发的小区自来水实时监控管理系统&#xff0c;系统包含超级管理员&#xff0c;系统管理员、用户角色&#xff0c;功能如下&#xff1a; 超级管理员&#xff1a;管理员管理&#xff1b;楼栋管理&#xff1b;租户管理、用水管理&…

糖尿病视网膜病变,黄斑病变,年龄相关检测研究(Matlab代码)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【Git分支操作---讲解二】

Git分支操作---讲解二 查看分支创建分支切换分支修改分支切换分支合并分支合并分支【冲突】(只会修改主分支不会修改其他分支)什么时候会有冲突&#xff1f; 查看分支 创建分支 切换分支 修改分支 切换分支 合并分支 合并分支【冲突】(只会修改主分支不会修改其他分支) 什么时…

python 打印沁园春 雪 居中对齐 文本对齐

以下是python 中使用 DebugInfo 模块居中对齐打印《沁园春・雪》的效果 引入模块 pip install DebugInfopython代码 # -*- coding:UTF-8 -*-# region 引入必要依赖 from DebugInfo.DebugInfo import * # endregion诗文 沁园春 雪 作者: 毛主席 北国风光&#xff0c;千里冰封…

Blazor前后端框架Known-V1.2.13

V1.2.13 Known是基于C#和Blazor开发的前后端分离快速开发框架&#xff0c;开箱即用&#xff0c;跨平台&#xff0c;一处代码&#xff0c;多处运行。 Gitee&#xff1a; https://gitee.com/known/KnownGithub&#xff1a;https://github.com/known/Known 概述 基于C#和Blazo…

PySpark安装及WordCount实现(基于Ubuntu)

先盘点一下要安装哪些东西&#xff1a; VMwareubuntu 14.04&#xff08;64位&#xff09;Java环境&#xff08;JDK 1.8&#xff09;Hadoop 2.7.1Spark 2.4.0&#xff08;Local模式&#xff09;Pycharm &#xff08;一&#xff09;Ubuntu VMware 和 ubuntu 14.04&#xff08;…

数据结构与算法:计算机科学的基石

文章目录 数据结构&#xff1a;构建数据的框架算法&#xff1a;问题的解决方案编程语言&#xff1a;实现数据结构的工具结论 &#x1f389;欢迎来到数据结构学习专栏~数据结构与算法&#xff1a;计算机科学的基石 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&…

python schedule库使用教程

schedule 是一个 Python 库&#xff0c;用于在指定的时间间隔或特定时间点执行任务。它可以帮助你创建定时任务&#xff0c;例如定时运行函数、脚本等。以下是一个简单的 schedule 库的使用教程。 安装 首先&#xff0c;你需要安装 schedule 库。你可以使用以下命令通过 pip …

速通蓝桥杯嵌入式省一教程:(八)ADC测量模拟电压

ADC(Analog to Digital Converter)&#xff0c;模拟数字转换器&#xff0c;是电子工程师必须掌握的一个内容。由于单片机、计算机等是由0和1组成的&#xff0c;因此其无法直接测量或使用连续的模拟信号&#xff0c;需要用ADC将模拟信号转换为离散的数字信号。ADC的具体原理在此…

uni-app 打包生成签名Sha1

Android平台打包发布apk应用&#xff0c;需要使用数字证书&#xff08;.keystore文件&#xff09;进行签名&#xff0c;用于表明开发者身份。 可以使用JRE环境中的keytool命令生成。以下是windows平台生成证书的方法&#xff1a; 安装JRE环境&#xff08;推荐使用JRE8环境&am…

CH02_重构的原则(什么是重构、为什么重构、何时重构)

什么是重构 重构&#xff08;名词&#xff09;&#xff1a;对软件内部结构的一种调整&#xff0c;目的是在不改变软件可观察行为的前提下&#xff0c;提高其可理解性&#xff0c;降低其修改成本。 重构&#xff08;动词&#xff09;&#xff1a;使用一系列重构手法&#xff0…

ThinkPHP6.0+ 使用Redis 原始用法

composer 安装 predis/predis 依赖&#xff0c;或者安装php_redis.dll的扩展。 我这里选择的是predis/predis 依赖。 composer require predis/predis 进入config/cache.php 配置添加redis缓存支持 示例&#xff1a; <?php// -----------------------------------------…

【RabbitMQ】RabbitMQ整合SpringBoot案例

文章目录 1、前情提要【RabbitMQ】2、RabbitMQ-SpringBoot案例 -fanout模式2.1 实现架构总览2.2 具体实现2.2.1生产者2.2.1消费者 1、前情提要【RabbitMQ】 【RabbitMQ】消息队列-RabbitMQ篇章 RabbitMQ实现流程 2、RabbitMQ-SpringBoot案例 -fanout模式 2.1 实现架构总览…

Allegro如何设置Net Class在物理和间距规则中同步操作指导

Allegro如何设置Net Class在物理和间距规则中同步操作指导 在用Allegro设置规则的时候,设置net class是必要的操作,时常需要在物理和间距规则都设置好Class,如果物理和间距规则中都单独去设置的话比较费时间。如下图Net Class 下面介绍如何将物理和间距规则中的Class同步起来…

jsp 协同过滤 图书管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 协同过滤 图书管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境 为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为My…

docker限制容器日志大小

文章目录 业务场景问题排查彻底解决 业务场景 我们公司做交通相关业务&#xff0c;我们部门主要负责信控服务&#xff0c;卖信号机的硬件产品和配套的信控平台 由于有部分小项目&#xff0c;可能只有几十个路口&#xff0c;客户预算有限&#xff0c;只给我们老旧的Windows ser…

Handler及相关的理论知识

前言 学安卓的都接触过Handler&#xff0c;许多老java项目中也有很多使用Handler进行网络通讯&#xff0c;或许现在我们都用kotlin&#xff0c;用协程&#xff0c;但咱也不能就把Handler忘了&#xff0c;本篇文章特此巩固Handler相关知识 是什么 Handler主要用于异步消息的处…