ElasticSearch - function_score (衰减函数 linear、exp、gauss 具体实例)

阅读本文需要先了解function_score的相关知识,请看 ElasticSearch - function_score 详解

1. 前言

很多变量都可以影响用户对于酒店的选择,像是用户可能希望酒店离市中心近一点,但是如果价格足够便宜,也愿意为了省钱,妥协选择一个更远的住处。如果我们只是使用一个 filter 排除所有市中心方圆 100 米以外的酒店,再用一个filter排除每晚价格超过100元的酒店,这种作法太过强硬,可能有一间房在 500米,但是超级便宜一晚只要10元,用户可能会因此愿意妥协住这间房。

为了解决这个问题,因此function_score查询提供了一组 衰减函数 (decay functions), 让我们有能力在两个滑动标准(如地点和价格)之间权衡。

2. function_score支持的衰减函数

2.1 三种衰减函数(linearexpgauss

function_score支持的衰减函数有三种,分别是 linearexpgausslinearexpgauss三种衰减函数的差别只在于衰减曲线的形状,在DSL的语法上的用法完全一样。

  • linear : 线性函数是条直线,一旦直线与横轴0相交,所有其他值的评分都是0。
  • exp : 指数函数是先剧烈衰减然后变缓。
  • guass(最常用) : 高斯函数则是钟形的,他的衰减速率是先缓慢,然后变快,最后又放缓。

在这里插入图片描述

2.2 衰减函数们 (linearexpgauss) 支持的参数
  • origin : 中心点,或是字段可能的最佳值,落在原点(origin)上的文档评分_score为满分1.0,支持数值、时间 以及 “经纬度地理座标点”(最常用) 的字段。
  • offset : 从 origin 为中心,为他设置一个偏移量offset覆盖一个范围,在此范围内所有的评分_score也都是和origin一样满分1.0。
  • scale : 衰减率,即是一个文档从origin下落时,_score改变的速度。
  • decay : 从 origin 衰减到 scale 所得的评分_score,默认为0.5 (一般不需要改变,这个参数使用默认的就好了)。

以上面的图为例:

  • 所有曲线(linear、exp、gauss)的origin都是40,offset是5,因此范围在40-5 <= value <= 40+5的文档的评分_score都是满分1.0
  • 而在此范围之外,评分会开始衰减,衰减率由scale值(此处是5)和decay值(此处是默认值0.5)决定,在origin +/- (offset + scale)处的评分是decay值,也就是在30、50的评分处是0.5分。
  • 也就是说,在origin + offset + scale或是origin - offset - scale的点上,得到的分数仅有decay分。

3. 具体实例

3.1 具体实例-1

先准备数据和索引,在ES插入三条数据,其中language是keywork类型,like是integer类型(代表点赞量):

{ "language": "java", "like": 5 }
{ "language": "python", "like": 10 }
{ "language": "go", "like": 15 }

like=15为中心,使用gauss函数:

GET 127.0.0.1/mytest/doc/_search
{
    "query": {
        "function_score": {
            "query": {
                "match_all": {}
            },
            "functions": [
                {
                    "gauss": {
                        "like": {
                            "origin": "15", //如果不设置offset,offset默认为0
                            "scale": "5",
                            "decay": "0.2"
                        }
                    }
                }
            ]
        }
    }
}
"hits": [
    {
        "_score": 1,
        "_source": { "language": "go", "like": 15 }
    },
    {
        "_score": 0.2, //因为改变了decay=0.2,所以当位于 origin-offset-scale=10 的位置时,分数为decay,就是0.2
        "_source": { "language": "python", "like": 10 }
    },
    {
        "_score": 0.0016,
        "_source": { "language": "java", "like": 5 }
    }
]
3.2 具体实例-2

假设有一个用户希望租一个离市中心近一点的酒店,且每晚不超过100元的酒店,而且与距离相比,我们的用户对价格更敏感,那麽使用衰减函数guass查询如下:

  • 其中把price语句的origin点设为50是有原因的,由于价格的特性一定是越低越好,所以0~100元的所有价格的酒店都应该认为是比较好的,而100元以上的酒店就慢慢衰减。

  • 如果我们将price的origin点设置成100,那麽价格低于100元的酒店的评分反而会变低,这不是我们期望的结果,与其这样不如将origin和offset同时设成50,只让price大于100元时评分才会变低

  • 虽然这样设置也会使得price小于0元的酒店评分降低没错,不过现实生活中价格不会有负数,因此就算price<0的评分会下降,也不会对我们的搜索结果造成影响(酒店的价格一定都是正的)。

  • 换句话说,其实只要把origin + offset的值设为100,origin或offset是什麽样的值都无所谓,只要能确保酒店价格在100元以上的酒店会衰减就好了。

GET 127.0.0.1/mytest/doc/_search
{
    "query": {
        "function_score": {
            "functions": [
                //第一个gauss加强函数,决定距离的衰减率
                {
                    "gauss": {
                        "location": {
                            "origin": {  //origin点设成酒店的经纬度座标
                                "lat": 51.5,
                                "lon": 0.12
                            },
                            "offset": "2km", //距离中心点2km以内都是满分1.0,2km外开始衰减
                            "scale": "3km"  //衰减率
                        }
                    }
                },
                //第二个gauss加强函数,决定价格的衰减率,因为用户对价格更敏感,所以给了这个gauss加强函数2倍的权重
                {
                    "gauss": {
                        "price": {
                            "origin": "50", 
                            "offset": "50",
                            "scale": "20"
                        }
                    },
                    "weight": 2
                }
            ]
        }
    }
}
以下是一个使用Java语言编写的elasticsearch function_score查询的示例代码,包含所有必要的语法: ```java import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder; import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders; import org.elasticsearch.index.query.functionscore.script.ScriptScoreFunctionBuilder; import org.elasticsearch.search.SearchHits; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.sort.SortBuilders; import org.elasticsearch.search.sort.SortOrder; import java.io.IOException; public class FunctionScoreExample { public static void main(String[] args) throws IOException { // 创建一个搜索源构建器 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); // 创建一个function_score查询构建器 FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery( QueryBuilders.matchAllQuery(), ScoreFunctionBuilders.randomFunction() ); // 设置查询权重 functionScoreQueryBuilder.boost(2.0f); // 创建一个排序构建器 sourceBuilder.sort(SortBuilders.fieldSort("timestamp").order(SortOrder.DESC)); // 将查询构建器添加到搜索源构建器中 sourceBuilder.query(functionScoreQueryBuilder); // 执行查询 SearchHits hits = ElasticsearchUtil.search("index_name", sourceBuilder); // 处理查询结果 for (SearchHit hit : hits.getHits()) { // 处理每个搜索结果 } } } ``` 其中,`ElasticsearchUtil`是一个自定义的工具类,用于与elasticsearch进行交互。在此示例中,我们使用`ScoreFunctionBuilders.randomFunction()`创建了一个随机评分函数,将其与`QueryBuilders.matchAllQuery()`组合使用来创建一个简单的function_score查询。我们还设置了查询权重和排序规则,并使用`ElasticsearchUtil`执行了查询。在实际使用中,您需要根据您的具体需求进行相应的调整和修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值