ElasticSearch - function_score详解

function_score内容较多,此篇主要是对function_score内容做系统性的讲解,之后会出几篇实际应用的方法,参考以下链接
1- ElasticSearch - function_score (field_value_factor具体实例)
2- ElasticSearch - function_score (衰减函数 linear、exp、gauss 具体实例)

1. 前言

在使用 Elasticsearch 进行全文搜索时,搜索结果默认会以文档的相关度进行排序,如果想要改变默认的排序规则,也可以通过sort指定一个或多个排序字段。但是使用sort排序过于绝对,它会直接忽略掉文档本身的相关度(根本不会去计算)。在很多时候这样做的效果并不好,这时候就需要对多个字段进行综合评估,得出一个最终的排序。Elasticsearch提供了function_score功能来满足我们的需求。

2. function_score简介

在使用ES进行全文搜索时,搜索结果默认会以文档的相关度进行排序,而这个 “文档的相关度”,是可以透过 function_score 自己定义的,也就是说我们可以透过使用function_score,来控制 “怎麽样的文档相关度更高” 这件事。

  • function_score是专门用于处理文档_scoreDSL,它允许爲每个主查询query匹配的文档应用加强函数, 以达到改变原始查询评分 score的目的。
  • function_score会在主查询query结束后对每一个匹配的文档进行一系列的重打分操作,能够对多个字段一起进行综合评估,且能够使用 filter 将结果划分爲多个子集 (每个特性一个filter),并为每个子集使用不同的加强函数。

3. function_score参数

3.1 function_score 提供了几种加强_score计算的函数:
  • weight : 设置一个简单而不被规范化的权重提升值。
    weight加强函数和 boost参数类似,可以用于任何查询,不过有一点差别是weight不会被Lucene nomalize成难以理解的浮点数,而是直接被应用 (boost会被nomalize)

    例如当 weight 爲 2 时,最终结果爲new_score = old_score * 2

  • field_value_factor : 将某个字段的值乘上old_score

    像是将 字段shareCount 或是 字段likiCount 作爲考虑因素,new_score = old_score * 那个文档的likeCount的值

  • random_score : 爲每个用户都使用一个不同的随机评分对结果排序,但对某一具体用户来说,看到的顺序始终是一致的。

  • 衰减函数 (linear、exp、guass) : 以某个字段的值为基准,距离某个值越近得分越高。

  • script_score : 当需求超出以上范围时,可以用自定义脚本完全控制评分计算,不过因为还要额外维护脚本不好维护,因此尽量使用ES提供的评分函数,需求真的无法满足再使用script_score

3.2 function_scroe其他辅助的参数
3.2.1 boost_mode

boost_mode决定 old_score 和 加强score 如何合并。

  • multiply(默认) : new_score = old_score * 加强score
  • sum : new_score = old_score + 加强score
  • min : old_score 和 加强score 取较小值,new_score = min(old_score, 加强score)
  • max : old_score 和 加强score 取较大值,new_score = max(old_score, 加强score)
  • replace : 加强score直接替换掉old_score,new_score = 加强score
3.2.2 score_mode

score_mode决定functions裡面的加强score们怎麽合併,会先合併加强score们成一个总加强score,再使用总加强score去和old_score做合併,换言之就是会先执行score_mode,再执行boost_mode

  • multiply (默认)
  • sum
  • avg
  • first : 使用首个函数(可以有filter,也可以没有)的结果作为最终结果。
  • max
  • min
3.2.3 max_boost

max_boost : 限制加强函数的最大效果,就是限制加强score最大能多少,但要注意不会限制old_score。

  • 如果加强score超过了max_boost限制的值,会把加强score的值设成max_boost的值。
  • 假设加强score是5,而max_boost是2,因为加强score超出了max_boost的限制,所以max_boost就会把加强score改为2。简单的说,就是加强score = min(加强score, max_boost)

4. function_score查询模板

如果要使用function_score改变分数,要使用function_score查询。简单的说,就是在一个function_score内部的query的全文搜索得到的_score基础上,给他加上其他字段的评分标准,就能够得到把 “全文搜索 + 其他字段” 综合起来评分的效果。

4.1 单个加强函数的查询模板
GET 127.0.0.1/mytest/doc/_search
{
    "query": {
        "function_score": {
            "query": {.....}, //主查询,查询完后这裡自己会有一个评分,就是old_score
            "field_value_factor": {...}, //在old_score的基础上,给他加强其他字段的评分,这裡会产生一个加强score
,如果只有一个加强function时,直接将加强函数名写在query下面就可以了
            "boost_mode": "multiply", //指定用哪种方式结合old_score和加强score成为new_score
            "max_boost": 1.5 //限制加强score的最高分,但是不会限制old_score
        }
    }
}
4.2 多个加强函数的查询模板

如果有多个加强函数,那就要使用functions来包含这些加强函数们,functions是一个数组,裡面放著的是将要被使用的加强函数列表。

可以为functions裡的加强函数指定一个filter,这样做的话,只有在文档满足此filter的要求,此filter的加强函数才会应用到文挡上,也可以不指定filter,这样的话此加强函数就会应用到全部的文挡上。

一个文档可以一次满足多条加强函数和多个filter,如果一次满足多个,那麽就会产生多个加强score,因此ES会使用score_mode定义的方式来合併这些加强score们,得到一个总加强score,得到总加强score之后,才会再使用boost_mode定义的方式去和old_score做合并。

例如: 下面的例子,field_value_factorgauss这两个加强函数会应用到所有文档上,而weight只会应用到满足filter的文档上,假设有个文档满足了filter的条件,那他就会得到3个加强score,这3个加强score会使用sum的方式合併成一个总加强score,然后才和old_score使用multiply的方式合并。

GET 127.0.0.1/mytest/doc/_search
{
    "query": {
        "function_score": {
            "query": {.....},
            "functions": [   //可以有多个加强函数(或是filter+加强函数),每一个加强函数会产生一个加强score,因
此functions会有多个加强score
                { "field_value_factor": ... },
                { "gauss": ... },
                { "filter": {...}, "weight": ... }
            ],
            "score_mode": "sum", //决定加强score们怎麽合併,
            "boost_mode": "multiply" //決定總加強score怎麼和old_score合併
        }
    }
}

5. 总结

不要执著在调整function_score上,文档相关度的调整非常玄,“最相关的文档” 是一个难以触及的模糊概念,每个人对文档排序有著不同的想法,这很容易使人陷入持续反覆调整,但是确没有明显的进展。为了避免跳入这种死循环,在调整function_score时,一定要搭配监控用户操作,才有意义。

例如:如果返回的文档是用户想要的高相关的文档,那麽用户就会选择前10个中的一个文档,得到想要的结果,反之,用户可能会来回点击,或是尝试新的搜索条件。一旦有了这些监控手段,想要调适完美的function_score就不是问题。

因此,调整function_score的重点在于,要透过监控用户、和用户互动,慢慢去调整我们的搜索条件,而不要妄想一步登天,第一次就把文档的相关度调整到最好,这几乎是不可能的,因为,连用户自己也不知道他自己想要什麽。

  • 10
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Java中使用Elasticsearch的Function Score API可以对搜索结果进行加权,以提高搜索结果的相关性。Function Score API提供了多种函数和算法,可以根据不同的需求进行调整。下面是Java代码中关于Elasticsearch的Function Score API的详解。 1. Function Score Query Function Score Query是使用Function Score API的最基本方法。以下是一个简单的例子: ```java FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery() .add(QueryBuilders.matchQuery("name", "Bob"), ScoreFunctionBuilders.weightFactorFunction(2)) .add(QueryBuilders.matchQuery("age", "30"), ScoreFunctionBuilders.weightFactorFunction(3)) .scoreMode("sum"); SearchQuery searchQuery = new NativeSearchQueryBuilder() .withQuery(functionScoreQueryBuilder) .build(); ``` 其中,add方法添加了两个查询条件,分别是匹配name为Bob和age为30的记录,weightFactorFunction方法设置了权重因子,这里分别为2和3。scoreMode方法设置了计算分数的方式,这里为求和。 2. Decay Functions Decay Functions提供了一种根据距离或时间进行衰减的方法,可以用来实现地理位置搜索、时间搜索等功能。以下是一个地理位置搜索的例子: ```java FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery() .add(QueryBuilders.matchAllQuery(), ScoreFunctionBuilders.weightFactorFunction(1)) .add(ScoreFunctionBuilders .gaussDecayFunction("location", new GeoPoint(40.715, -74.011), "1km") .setDecay(0.5) .setOffset("1km") .setWeight(2)) .scoreMode("sum"); SearchQuery searchQuery = new NativeSearchQueryBuilder() .withQuery(functionScoreQueryBuilder) .build(); ``` 其中,gaussDecayFunction方法设置了衰减函数为高斯衰减函数,参数分别为字段名、中心点、衰减半径。setDecay方法设置了衰减速率,这里为0.5。setOffset方法设置了衰减偏移量,这里为1km。setWeight方法设置了权重因子,这里为2。 3. Script Functions Script Functions可以使用脚本来自定义计算分数的逻辑,可以实现更加灵活的需求。以下是一个使用脚本计算分数的例子: ```java Script script = new Script(ScriptType.INLINE, "painless", "doc['age'].value * params.factor", Collections.singletonMap("factor", 2)); FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery() .add(QueryBuilders.matchAllQuery(), ScoreFunctionBuilders.weightFactorFunction(1)) .add(ScoreFunctionBuilders.scriptFunction(script)) .scoreMode("sum"); SearchQuery searchQuery = new NativeSearchQueryBuilder() .withQuery(functionScoreQueryBuilder) .build(); ``` 其中,script方法设置了脚本,使用了Painless语言,计算分数的逻辑为doc['age'].value * params.factor,其中params.factor为参数,这里为2。 总之,Elasticsearch的Function Score API提供了多种函数和算法,可以根据不同的需求进行调整。在Java代码中,可以使用FunctionScoreQueryBuilder和ScoreFunctionBuilders来构建查询条件和函数,实现对搜索结果的加权。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值