通过案例实战详解elasticsearch自定义打分function_score的使用

前言

elasticsearch给我们提供了很强大的搜索功能,但是有时候仅仅只用相关度打分是不够的,所以elasticsearch给我们提供了自定义打分函数function_score,本文结合简单案例详解function_score的使用方法,关于function-score-query的文档最权威的莫过于官方文档:
function_score官方文档

基本数据准备

我们创建一张新闻表,包含如下字段:

字段类型说明
idLong新闻ID
titlestring标题
tagsstring标签
read_countlong阅读数
like_countlong点赞数
comment_countlong评论数
rankdouble自定义权重
locationarrays文章发布经纬度
pub_timedate发布时间

创建elasticsearchMapping

PUT /news
{
  "mappings": {
    "properties": {
      "id": {
        "type": "long"
      },
      "title": {
        "type": "text",
        "analyzer": "standard"
      },
      "tags": {
        "type": "keyword"
      },
      "read_count": {
        "type": "long"
      },
     "like_count": {
        "type": "long"
      },
     "comment_count": {
        "type": "long"
      },
      "rank": {
        "type": "double"
      },
      "location": {
          "type": "geo_point"
        },
      "pub_time": {
        "type": "date",
        "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm||yyyy-MM-dd||epoch_millis"
      }
    }
  }
}

准备测试数据:

idtitletagsread_countcomment_countlike_countranklocationpub_time
1台风“杜苏芮”登陆福建晋江 多部门多地全力应对台风;杜苏芮;福建1000020006000118.55199,24.781442023-07-29 09:47
2受台风“杜苏芮”影响 北京7月29日至8月1日将有强降雨台风;杜苏芮;北京1000200600116.23128,40.220772023-06-29 14:49:38
3杭州解除台风蓝色预警信号台风;杭州10260.9120.21201,30.20842020-07-29 14:49:38

批量添加数据到elasticsearch中:

POST _bulk
{"create": {"_index": "news", "_id": 1}}
{"comment_count":600,"id":1,"like_count":2000,"location":[118.55199,24.78144],"pub_time":"2023-07-29 09:47","rank":0.0,"read_count":10000,"tags":["台风","杜苏芮","福建"],"title":"台风“杜苏芮”登陆福建晋江 多部门多地全力应对"}
{"create": {"_index": "news", "_id": 2}}
{"comment_count":60,"id":2,"like_count":200,"location":[116.23128,40.22077],"pub_time":"2023-06-29 14:49:38","rank":0.0,"read_count":1000,"tags":["台风","杜苏芮","北京"],"title":"受台风“杜苏芮”影响 北京7月29日至8月1日将有强降雨"}
{"create": {"_index": "news", "_id": 3}}
{"comment_count":6,"id":3,"like_count":20,"location":[120.21201,30.208],"pub_time":"2020-07-29 14:49:38","rank":0.99,"read_count":100,"tags":["台风","杭州"],"title":"杭州解除台风蓝色预警信号"}

random_score的使用

我们通过random_score理解一下weightscore_mode,boost_mode的作用分别是什么,先直接看Demo


GET /news/_search
{
  "query": {
    "function_score": {
      "query": {"match": {
        "title": "台风"
      }},
      "functions": [
        {
          "random_score": {}, 
          "weight": 1
        },
         {
          "filter": { "match": { "title": "杭州" } },
          "weight":42
        }
      ],
      "score_mode": "sum",
      "boost_mode": "replace"
    }
  }
}

对应JAVA查询代码:

        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.should(QueryBuilders.matchQuery("title","杭州"));
        FunctionScoreQueryBuilder.FilterFunctionBuilder[] filterFunctionBuilders = new FunctionScoreQueryBuilder.FilterFunctionBuilder[1];
        ScoreFunctionBuilder<RandomScoreFunctionBuilder> randomScoreFilter = new RandomScoreFunctionBuilder();
        ((RandomScoreFunctionBuilder) randomScoreFilter).seed(2);
        filterFunctionBuilders[0] = new FunctionScoreQueryBuilder.FilterFunctionBuilder(randomScoreFilter);
        FunctionScoreQueryBuilder query = QueryBuilders.functionScoreQuery(queryBuilder, filterFunctionBuilders).scoreMode(FunctionScoreQuery.ScoreMode.SUM).boostMode(CombineFunction.SUM);
        SearchSourceBuilder searchSourceBuilder= new SearchSourceBuilder().query(query);
        SearchRequest searchRequest= new SearchRequest().searchType(SearchType.DFS_QUERY_THEN_FETCH).indices("news").source(searchSourceBuilder);
        SearchResponse response =  restClient.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        String searchSource;
        for (SearchHit hit : hits)
        {
            searchSource = hit.getSourceAsString();
            System.out.println(searchSource);
        }

查询结果:
image.png

这个查询使用的function_scorequery中通过title搜索“台风”,在functions我们增加了两个打分,一个是random_score,随机生成一个得分,得分的weight权重是1,第二个是如果标题中有“杭州”,得分权重为42,

  • random_score
    顾名思义就是生成一个(0,1)之间的随机得分,我能想到的一个应用场景是,有一天产品要求:每个人看到新闻都不一样,要做到“千人千面”,而且只给你一天的时间,这样我们就可以使用random_score,每次拉取的数据都是随机的,每个人看到的新闻都是不一样的,这个随机查询比Mysql实现简单多了,0成本实现了“千人千面”。

  • weight
    这个就是给生成的得分增加一个权重,在上面的Demo中,我们第一个 weight=1,第二个weight=42,从搜索结果得分可以看出“杭州解除台风蓝色预警信号”这条得分是42.40192,而下面的只有0.8194501,因为增加了42倍的权重。

  • score_mode

score_mode的作用是对functions中计算出来的多个得分做汇总计算,比如我用了是sum,就是指将上面random_score得到的打分和filter中得到的42分相加,也就是说第一条42.40192得分是random_score生成了0.40192再加上filter中得到了42分。score_mode默认是采用multiply,总共有6种计算方式:

random_score函数计算方式
multiplyscores are multiplied (default)
sumscores are summed
avgscores are averaged
firstthe first function that has a matching filter is applied
maxmaximum score is used
minminimum score is used
  • boost_mode

boost_mode作用是将functions得到的总分数和我们query查询的得到的分数做计算,比如我们使用的是replace就是完全使用functions中的得分替代query中的得分,boost_mode总共有6种计算方式:

boost_mode函数得分计算方式
multiplyquery score and function score is multiplied (default)
replaceonly function score is used, the query score is ignored
sumquery score and function score are added
avgaverage
maxmax of query score and function score
minmin of query score and function score

script_score的使用

script_score就是用记可以通过各种函数计算你文档中出现的字段,算出一个自己想要的得分,我们直接看Demo

image.png

GET /news/_search
{
  "query": {
    "function_score": {
      "query": {
        "match": { "title": "台风" }
      },
      "script_score": {
        "script": {
          "params": {
            "readCount": 1,
            "likeCount":5,
            "commentCount":10
          },
          "source": "Math.log(params.readCount* doc['read_count'].value +params.likeCount* doc['like_count'].value+params.commentCount* doc['comment_count'].value) "
        }
      },
      "boost_mode": "multiply"
    }
  }
}

每篇新闻有阅读数点赞数据评论数,我们可以通过这三个指标算出一个分值来评价一篇文章的热度,然后将这个热度和query中的得分相乘,这样热度很高的文章可以排到更前面。在这个Demo中我使用了一个简单的加权来计算文章热度,一般来说阅读数是最大的,点赞数次之,评论数是最小的。

文章热度 = L o g ( 评论数 × 10 + 点赞数 × 5 + 阅读数 ) 文章热度=Log(评论数\times 10+点赞数\times5+阅读数) 文章热度=Log(评论数×10+点赞数×5+阅读数)

这里为了演示,简单算一下文章热度,真实的要比这个复杂的多,可能不同种类的文章重要性也是不一样的。

field_value_factor的使用

field_value_factor可以理解成elasticsearch给你一些内置的script_score,每次写script_score必定不是太方便,如果有一些内置的函数,开箱即用就方便多了,我们直接看Demo

GET /news/_search
{
    "query": {
        "function_score": {
            "query": {
                "match": {
                    "title": "台风"
                }
            },
            "field_value_factor": {
                "field": "rank",
                "factor": 10,
                "modifier": "sqrt",
                "missing": 1
            },
            "boost_mode": "multiply"
        }
    }
}

这里的field_value_factor就对相当script_scoresqrt(10 * doc['rank'].value),这里的factor是乘以多少倍,默认是1倍,missing是如果没有这个字段默认值为1,modifier是计算函数,field是要计算的字段。

modifier计算函数有以下类型可以选择

modifier函数得分计算方式
noneDo not apply any multiplier to the field value
logTake the common logarithm of the field value. Because this function will return a negative value and cause an error if used on values between 0 and 1, it is recommended to use log1p instead.
log1pAdd 1 to the field value and take the common logarithm
log2pAdd 2 to the field value and take the common logarithm
lnTake the natural logarithm of the field value. Because this function will return a negative value and cause an error if used on values between 0 and 1, it is recommended to use ln1p instead.
ln1pAdd 1 to the field value and take the natural logarithm
ln2pAdd 2 to the field value and take the natural logarithm
squareSquare the field value (multiply it by itself)
sqrtTake the square root of the field value
reciprocalReciprocate the field value, same as 1/x where x is the field’s value

衰减函数Decay functions的使用

衰减函数可以理解成计算文档中某一个字段与给定值的距离,如果距离越近得分就越高,距离越远得分就越低,这个就比较适用于新闻发布时间的衰减了,越久前发布的新闻,得分应该越小,排序越往后。我们直接看Demo

GET /news/_search
{
    "query": {
        "function_score": {
            "query": {
                "match": {
                    "title": "台风"
                }
            },
            "functions": [
                {
                    "gauss": {
                        "pub_time": {
                            "origin": "now",
                            "offset": "7d",
                            "scale": "60d",
                            "decay": 0.9
                        }
                    }
                },
                {
                    "exp": {
                        "location": {
                            "origin": {
                                "lat": 120.21551,
                                "lon": 30.25308
                            },
                            "offset": "50km",
                            "scale": "50km",
                            "decay": 0.1
                        }
                    }
                }
            ],
            "score_mode": "sum", 
            "boost_mode": "sum"
        }
    }
}

搜索结果:
image.png

衰减函数有3种,分别为gauss高斯函数、lin线程函数、exp对数函数,具体的计算公式可以参考官方文档,这里我们主要理解衰减函数的4个参数作用是什么。

image.png

  • origin
    可以理解成计算距离的原点,比如上面计算新闻发布时间的原点是当前时间,计算经纬度的原点是用户搜索位置,比如我在杭州,那么origin就是杭州的经纬度

  • offset
    这个偏移量可以理解成不需要衰减的距离,比如在上面的Demo中,距离pub_timeoffset为7d,意思是说近7天内发布的新闻都不需要衰减,得分直接为1。计算经纬度中的offset为50km意思是说距离用户50km里的新闻不需要衰减,50km内的基本都是杭州本地的新闻,就没必要衰减了。

  • scaledecay
    这两个参数可以参考官方给的三种函数衰减图,scaledecay表示距离为scale后得分衰减到原来的scale倍。比如上面时间衰减offset=7d, scale=60d,decay= 0.9加起来的意思就是7天内的新闻不衰减,67天(7d+60d)前的新闻得分为0.9,在经纬度衰减中offset=50km, scale=50km,decay= 0.1的意思是50km内的距离不衰减,100km(50km+50km)外的数据得分为0.1。

总结

elasticsearchfunction_score给我提供了好几种很灵活的自定义打分策略,在实际项目中需要根据自己的需求合理的组合这些打分策略并调整对应参数才能满足自己的搜索需求,本文主要介绍function_score的使用,接下来我会根据一个实际的搜索应用介绍一下如何组合、设置这些函数以达到比较理解的搜索效果。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Spring】深究SpringBoot自动装配原理

文章目录 前言1、main入口2、SpringBootApplication3、EnableAutoConfiguration4、AutoConfigurationImportSelector4.1、selectImports()4.2、getAutoConfigurationEntry()4.3、getCandidateConfigurations()4.4、loadFactoryNames() 5、META-INF/spring.factories6、总结 前言…

Nginx实现反向代理和负载均衡

Nginx安装 本文章主要介绍下&#xff0c;如何使用Nginx来实现反向代理和负载均衡&#xff0c;Nginx安装和基础知识&#xff0c;可参考我的这篇文章 Nginx安装。 Nginx实现反向代理 实现反向代理需要准备两台Nginx服务器。一台Nginx服务器A&#xff0c;ip为 192.168.206.140&…

浅谈机器视觉

目录 1.什么是机器视觉 2.学习机器视觉需要掌握的知识 3.机器视觉的由来 4.机器视觉带来的福利 1.什么是机器视觉 机器视觉&#xff08;Computer Vision&#xff09;是人工智能领域中的一个分支&#xff0c;旨在通过模仿人类的视觉系统&#xff0c;使计算机能够理解和解释图…

【Leetcode】(自食用)找到消失的数字

step by step. 题目&#xff1a; 给你一个含 n 个整数的数组 nums &#xff0c;其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字&#xff0c;并以数组的形式返回结果。 示例 1&#xff1a; 输入&#xff1a;nums [4,3,2,7,8,2,3,1] 输…

Stable Diffusion教程(6) - 扩展安装

打开stable diffusion webUI界面 加载插件列表 依次点击扩展->可用->加载自 搜索插件 首先在搜索框输入你要安装的插件&#xff0c;然后点击插件后面的安装按钮 如果你需要的插件这里面没有找到&#xff0c;可通过通网址安装的方式安装。 在git仓库网址输入框输入的你插件…

分享 一个类似 ps 辅助线功能

效果图片&#xff1a; 提示&#xff1a;这里的样式我做边做了修改&#xff0c;根据个人情况而定。 //你也可以npm下载 $ npm install --save vue-ruler-tool特点 没有依赖可拖动的辅助线快捷键支持 开始使用 1. even.js /*** description 绑定事件 on(element, event, han…

FPGA项目设计:数字时钟

项目要求&#xff1a; 设计一个数字时钟&#xff0c;数码管前两位显示小时&#xff0c;数码管中间两位显示分钟&#xff0c;数码管后面两位显示秒。 项目设计&#xff1a; 系统框架图&#xff1a; 计数模块时序图&#xff1a; 代码实现&#xff1a; 计数模块&#xff1a; /…

举个栗子~Quick BI 技巧(2):创建柱线组合图

上一期举个栗子为数据粉们分享了如何简单几步创建趋势折线图&#xff0c;有一些数据粉发来疑问&#xff1a;如何利用 Quick BI 制作柱线图呢&#xff1f; 线柱图是一种非常重要且常用的组合图表&#xff0c;可以将两组数据在同一个表中直观的表达。今天的栗子&#xff0c;我们…

什么是头脑风暴法,有哪些原则?

1. 什么是头脑风暴法&#xff1f; 头脑风暴法&#xff08;Brainstorming&#xff09;是一种用于创造性思维和问题解决的方法。它旨在通过集体讨论和思维碰撞&#xff0c;激发团队成员的创造力和想象力&#xff0c;从而产生新的创意和解决方案。 在头脑风暴会议中&#xff…

【项目方案】OpenAI流式请求实现方案

文章目录 实现目的效果比对非stream模式stream模式实现方案方案思路总体描述前端方案对比event-source-polyfill代码示例前端实现遇到的问题与解决方法后端参考资料时序图关键代码示例后端实现时遇到的问题与解决方法实现目的 stream是OpenAI API中的一个参数,用于控制请求的…

Dockerfile构建Tomcat镜像(源码)

Dockerfile构建Tomcat镜像 目录 Dockerfile构建Tomcat镜像 1、建立工作目录 2、编写Dockerfile文件 3、构建镜像 4、测试容器 5、浏览器访问测试&#xff1a; 1、建立工作目录 [roothuyang1 ~]# mkdir tomcat[roothuyang1 ~]# cd tomcat/[roothuyang1 tomcat]# lsapach…

了解垃圾回收算法

点击下方关注我&#xff0c;然后右上角点击...“设为星标”&#xff0c;就能第一时间收到更新推送啦~~~ 垃圾回收&#xff08;Garbage Collect&#xff09;是Java语言中的一种自动内存管理机制&#xff0c;用于自动回收不再使用的对象所占用的内存空间。Java虚拟机会自动追踪和…

C# Microsoft消息队列服务器的使用 MSMQ

先安装消息队列服务器 private static readonly string path ".\\Private$\\myQueue";private void Create(){if (!MessageQueue.Exists(path)){MessageQueue.Create(path);}}private void Send(){Stopwatch stopwatch new Stopwatch();stopwatch.Start();Message…

【爬虫逆向案例】某易云音乐(评论)js逆向—— params、encSecKey解密

声明&#xff1a;本文只作学习研究&#xff0c;禁止用于非法用途&#xff0c;否则后果自负&#xff0c;如有侵权&#xff0c;请告知删除&#xff0c;谢谢&#xff01; 【爬虫逆向案例】某易云音乐&#xff08;评论&#xff09;js逆向—— params、encSecKey解密 1、前言2、行动…

国标GB28181安防视频平台EasyGBS大批量通道接入后,创建角色接口未响应的排查

国标GB28181协议视频平台EasyGBS是基于国标GB28181协议的视频云服务平台&#xff0c;支持多路设备同时接入&#xff0c;并对多平台、多终端分发出RTSP、RTMP、FLV、HLS、WebRTC等格式的视频流。平台可提供视频监控直播、云端录像、云存储、检索回放、智能告警、语音对讲、平台级…

Python 一篇入门

目录 Python 的简介与特点 Python支持多种编程风格 解释运行 跨平台 可扩展强 可嵌入 丰富的库 Python版本选择 Python开发环境搭建 认识Python解释器 快速入门 变量和赋值 动态类型 变量命名规则 认识 "数字" 认识 "字符串" 认识 "…

TSINGSEE青犀视频汇聚平台EasyCVR视频广场面包屑侧边栏支持拖拽操作

TSINGSEE青犀视频汇聚平台EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有GB28181、RTSP/Onvif、RTMP等&#xff0c;以及厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等&#xff0c;能对外分发RTSP、RTMP、FLV、HLS、Web…

mysql 、sql server 常见的区别

&#xff2e;&#xff35;&#xff2c;&#xff2c;   处理 MySQL IFNULL(col , val) SQL Server ISNULL(col,val) 表名、列名等 一般不推荐用保留字 &#xff0c;如果非要保留字 MySQL 用用着重号&#xff0c;即 反引号 包括 select col from GROUP SQL Server 用用着重号…

【GO】go语言入门实战 —— 命令行在线词典

文章目录 程序介绍抓包代码生成生成request body解析respond body完整代码 字节青训营基础班学习记录。 程序介绍 在运行程序的时候以命令行的形式输入要查询的单词&#xff0c;然后程序返回单词的音标、释义等信息。 示例如下&#xff1a; 抓包 我们选择与网站https://fany…

Docker Compose 使用方法

目录 前言 安装 Docker Compose Ubuntu 安装与更新 Red Hat 安装与更新 验证是否安装 Docker Compose 创建 docker-compose.yml 文件 创建一个MySQL 与 tomcat 示例 使用Docker Compose启动服务 前言 Docker Compose 是一个工具&#xff0c;旨在帮助定义和 共享多容器…