Elasticsearch搜索功能的实现(六)-- function score详解

发布时间 2023-04-18 23:36:16作者: gdwkong

一 、function score详解

1.1 function score 查询中包含四部分内容:

1)原始查询条件:query部分,基于这个条件搜索文档,并且基于BM25算法给文档打分,原始算分(query score)

2)过滤条件:filter部分,符合该条件的文档才会重新算分

3)算分函数:符合filter条件的文档要根据这个函数做运算,得到的函数算分(function score);

1.2 四种算分函数:

  • weight:函数结果是常量
  • field_value_factor:以文档中的某个字段值作为函数结果
  • random_score:以随机数作为函数结果
  • script_score:自定义算分函数算法

1.3 运算模式

算分函数的结果、原始查询的相关性算分,两者之间的运算方式,包括:

  • multiply:相乘
  • replace:用function score替换query score
  • 其它,例如:sum、avg、max、min
注意,搜索时,参与打分的字段越多,查询的性能也越差。因此这种多条件查询时,建议这样做: 
* 搜索框的关键字搜索,是全文检索查询,使用must查询,参与算分;
* 其它过滤条件,采用filter查询。不参与算分;
* must:必须匹配的条件,可以理解为“与”
* should:选择性匹配的条件,可以理解为“或”
* must_not:必须不匹配的条件,不参与打分
* filter:必须匹配的条件,不参与打分**

二、java 实现示例

Map<String, JsonData> gaussParams = CollectionUtils.newHashMap(8);
gaussParams.put("origin",JsonData.of(LocalDate.now().toString()));
gaussParams.put("scale",JsonData.of("7d"));
gaussParams.put("offset",JsonData.of("0"));
gaussParams.put("decay",JsonData.of(0.5));

//高斯衰减函数
String  decayDateGauss = "decayDateGauss(params.origin, params.scale, params.offset, params.decay, doc['pubDate'].value)";

/**
* weight 为每个文档应用一个简单的而不被正则化的权重提升值:当 weight 为 2 时,最终结果为 2 * _score
* field_value_factor 使用这个值来修改 _score,如将流行度或评分作为考虑因素。
* random_score 为每个用户都使用一个不同的随机分数来对结果排序,但对某一具体用户来说,看到的顺序始终是一致的。
* Decay functions — linear, exp, gauss 以某个字段的值为标准,距离某个值越近得分越高。
* script_score 如果需求超出以上范围时,用自定义脚本完全控制分数计算的逻辑。 
* 它还有一个属性boost_mode可以指定计算后的分数与原始的_score如何合并,有以下选项:
*   multiply 将分数与函数值相乘(默认)
*   sum 将分数与函数值相加
*   min 分数与函数值的较小值
*   max 分数与函数值的较大值
*   replace 函数值替代分数
 * */
nativeQueryBuilder.withQuery(
                f -> f.functionScore(
                        fs -> fs.query(q -> q.bool(boolBuilder.build()))
                                .functions( FunctionScore.of(func -> func.filter(
                                                        fq -> fq.match(ft -> ft.field("title").query(keyword)))
                                                .weight(10.0)
                                        ),
                                        FunctionScore.of(func -> func.filter(
                                                        fq -> fq.match(ft -> ft.field("content").query(keyword)))
                                                .fieldValueFactor(v ->v.field("id").factor(0.5))
                                        ),
                                        FunctionScore.of(func -> func.filter(
                                                        fq -> fq.match(ft -> ft.field("companies").query(keyword)))
                                                .randomScore(v -> v.field("companies"))
                                        ),
                                        FunctionScore.of(func -> func.scriptScore(fq -> fq.script(
                                                                i -> i.inline(il -> il.source(decayDateGauss).params(gaussParams))
                                                        )
                                                )
                                        )
                                )
                                .scoreMode(FunctionScoreMode.Sum)
                                .boostMode(FunctionBoostMode.Sum)
                                .minScore(1.0)
                )
        );

相应的DSL语句
image

查询结果
image

至此关于es的搜索功能系列暂时告一段落。