顿搜
04. ES文档评分查询——ElasticSearch搜索专栏
[TOC]
一、Constant Score查询
如果不想让检索词频率TF(Term Frequency)对搜索结果排序有影响
只想过滤某个文本字段是否包含某个词,可以使用Constant Score将查询语句包装起来。
使用filter和constant_score进行处理。
1.1 DSL方式
GET /hotel/_search
{
"_source": ["amenities"],
"query": {
"constant_score": { //满足条件即打分为1
"filter": {
"match": { //查询设施中包含“停车场”的文档
"amenities": "停车场"
}
}
}
}
}在Constant Score搜索中,参数boost可以控制命中文档的得分,默认值为1.0
GET /hotel/_search
{
"_source": ["amenities"],
"query": {
"constant_score": {
"boost": 2.0, //设置Constant Score查询命中文档的得分为2.0
"filter": {
"match": {
"amenities": "停车场"
}
}
}
}
}1.2 Java 客户端方式
在Java客户端上构建Constant Score搜索时,可以使用ConstantScoreQueryBuilder类的实例进行构建
public void constantScoreSearch() {
//新建搜索请求
SearchRequest searchRequest = new SearchRequest("hotel");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//构建设施包含“停车场”的constant score查询
ConstantScoreQueryBuilder constantScoreQueryBuilder = new ConstantScoreQueryBuilder(
QueryBuilders.termQuery("amenities", "停车场"));
searchSourceBuilder.query(constantScoreQueryBuilder);
constantScoreQueryBuilder.boost(2.0f);
searchRequest.source(searchSourceBuilder); //设置查询
printResult(searchRequest); //打印结果
}二、Function Score查询
当使用ES进行搜索时,命中的文档默认按照相关度进行排序。
有些场景下用户需要干预该“相关度”,此时就可以使用Function Score查询。
使用function_score进行查询可以让用户修改文档的评分。
要使用function_score进行查询,必须定义一个查询以及一个或多个函数,这些函数将为查询返回的每个文档计算一个新的评分
也就是修改返回结果中_score字段的值
Elasticsearch为用户预定义了如下函数
- weight:表示为每个文档应用一个简单的权重:当weight为2时,最终结果为2 *_score。
- field_value_factor:表示使用这个值来修改_score。
- random_score:表示为每个用户都使用一个不同的随机评分。
- 衰减函数:包括linear、exp、gauss等函数。
- script_score:表示如果需求超出以上几种函数的范围,用户可以使用自定义脚本控制评分的计算。
2.1 DSL方式
GET /hotel/_search
{
"_source": ["title","city"],
"query": {
"function_score": {
"query": { //查询符合条件的文档
"term": {
"city": {
"value": "北京"
}
}
},
"functions": [ //定义函数
{ //此处只定义了一个函数:随机数函数
"random_score": {}
}
],
"score_mode": "sum" //最终分数是各个函数的加和值
}
}
}2.2 Java 客户端方式
在Java客户端中使用Function Score进行查询时,
可以调用ScoreFunctionBuilders.randomFunction()方法新建一个随机函数,
然后将该随机函数的实例传给QueryBuilders.functionScoreQuery()方法生成FunctionScoreQueryBuilder的实例
public void functionScoreSearch() {
//创建搜索请求
SearchRequest searchRequest = new SearchRequest("hotel");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//构建term查询
TermQueryBuilder termQuery = QueryBuilders.termQuery("city", "北京");
//构建随机函数
ScoreFunctionBuilder<?> scoreFunction = ScoreFunctionBuilders.randomFunction();
//构建Function Score查询
FunctionScoreQueryBuilder funcQuery = QueryBuilders.functionScoreQuery(
termQuery, scoreFunction).boostMode(CombineFunction.SUM);
searchSourceBuilder.query(funcQuery);
searchRequest.source(searchSourceBuilder); //设置查询请求
printResult(searchRequest); //打印搜索结果
}2.3 weight权重函数查询
GET /dbindex/_search
{
"query": {
"function_score": {
"query": { "match_all": {} },
"boost": "5",
"functions": [
{
"filter": { "match": { "test": "bar" } },
"weight": 1
},
{
"filter": { "match": { "test": "cat" } },
"weight": 2
}
]
}
}
}2.4 field_value_factor
可以调用field_value_factor函数通过文档中的某一个字段来计算评分
GET /dbindex/_search
{
"query": {
"function_score": {
"field_value_factor": {
"field": "my-int", // 表示要从文档中提取的字段
"factor": 1.2, // 表示字段值相乘的可选因子,默认值为1
"modifier": "sqrt",// 表示使用的计算公式, 默认为none
"missing": 1
}
}
}
}以上语句中的函数将转化为以下公式来计算评分, sqrt(1.2 * doc['my-int'].value)
modifier中可选的公式以及各个公式的含义:
- none: 不做任何计算
- log:取字段值的常用对数
- log1p:在字段值上加1,然后取常用对数
- log2p:在字段值上加2,然后取常用对数
- ln:取字段值的自然对数
- ln1p:在字段值上加1,然后取自然对数
- ln2p:在字段值上加2,然后取自然对数
- square: 取字段值的平方
- sqrt: 取字段值的平方根
- reciprocal: 取字段值的倒数
举个例子
GET /dbindex/_search
{
"query": {
"function_score": {
"query": {
"multi_match": {
"query": "popularity",
"fields": [ "title", "content" ]
}
},
"field_value_factor": {
"field": "votes",
"modifier": "log1p"
}
}
}
}最终的分数计算公式为:new_score = old_score * log(1 + number_of_votes)
2.5 random_score函数查询
GET /dbindex/_search
{
"query": {
"function_score": {
"query": { "match_all": {} },
"boost": "5",
"functions": [
{
"filter": { "match": { "test": "bar" } },
"random_score": {},
"weight": 23
},
{
"filter": { "match": { "test": "cat" } },
"weight": 42
}
],
"max_boost": 42,
"score_mode": "max", // 最终分数是各个函数最高分
"boost_mode": "multiply",
"min_score": 42
}
}
}score_mode:
- multiply: 评分的倍数
- sum: 评分之和
- avg: 评分的平均值
- first: 第一个匹配改文档的评分
- max: 评分中最高的的分数
- min: 评分中最低的分数
2.6 script_score脚本分数
script_score函数允许用户嵌套一个查询条件,并使用脚本表达式计算评分
GET /dbindex/_search
{
"query": {
"function_score": {
"query": {
"match": { "message": "Elasticsearch" }
},
"script_score": {
"script": {
"source": "Math.log(3 + doc['my-int'].value)"
}
}
}
}
}
- 所有文档分数都是正的32位浮点数。
- 如果script_score函数计算出来更精确的评分,它将被转换为最接近的32位浮点数。
- 必须保证评分是非负的,否则Elasticsearch将会返回一个错误信息。
三、提高评分查询
提高评分(boosting)查询不同于布尔查询,在布尔查询中只要一个子查询的条件不匹配,那么此文档数据就不符合要求。
提高评分查询其实是降低文档评分
比如查询条件是"name = 'clay' and address ='china'",对于只满足部分条件的文档数据,不是不返回,而是降低显示的优先级(也就是评分字段的值)
查询content字段中是否包含apple,并对包含pie的文档数据做降级处理(降低评分)
GET /dbindex/_search
{
"query": {
"boosting": {
"positive": {
"term": {
"content": "apple"
}
},
"negative": {
"term": {
"content": "pie"
}
},
"negative_boost": 0.5 // 此值小于1表示降低评分,大于1表示提高评分
}
}
}四、最佳匹配查询
dis_max指的是在文档匹配评分中,只将最佳匹配的评分作为查询的评分结果返回。
GET /dbindex/_search
{
"query": {
"dis_max": {
"queries": [
{ "match": { "title": "brown fox" }},
{ "match": { "body": "brown fox" }}
],
"tie_breaker": 0
}
}
}