默认情况下,即不设置 field 时会使用 Lucene doc ids 作为随机源去生成随机值,但是这会消耗大量内存,官方建议可以设置 field 为 _seq_no ,主要注意的是,即使指定了相同的 seed ,随机值某些情况下也会改变,这是因为一旦字段进行了更新,_seq_no 也会更新,进而导致随机源发生变化。
多个函数组合示例:
GET /_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 } } }
上例 functions 中设置了两个打分函数:
•一个是 random_score 随机打分,并且 weight 是 23•另一个只有 weight 是 42
假设:
•第一个函数随机打分得到了 0.1 ,再与 weight 相乘就是 2.3•第二个函数只有 weight ,那么这个函数得到的分数就是 weight 的值 42
score_mode 设置为了 max,意思是取两个打分函数的最大值作为 func_score,对应上述假设也就是 2.3 和 42 两者中的最大值,即 func_score = 42
boost_mode 设置为了 multiply,就是把原来的 query_score 与 func_score 相乘就得到了最终的 score 分数。
参数 score_mode 指定多个打分函数如何组合计算出新的分数:
•multiply : 分数相乘(默认)•sum : 相加•avg : 加权平均值•first : 使用第一个 filter 函数的分数•max : 取最大值•min : 取最小值
为了避免新的分数的数值过高,可以通过 max_boost 参数去设置上限。
需要注意的是:不论我们怎么自定义打分,都不会改变原始 query 的匹配行为,我们自定义打分,都是在原始 query 查询结束后,对每一个匹配的文档进行重新算分。
为了排除掉一些分数太低的结果,我们可以通过 min_score 参数设置最小分数阈值。
field_value_factor
field_value_factor 使用字段的数值参与计算分数。
例如使用 likes 点赞数字段进行综合搜索:
{ "query": { "function_score": { "query": { "match": { "message": "elasticsearch" } }, "field_value_factor": { "field": "likes", "factor": 1.2, "missing": 1, "modifier": "log1p" } } } }
说明:
•field : 参与计算的字段。•factor : 乘积因子,默认为 1 ,将会与 field 的字段值相乘。•missing : 如果 field 字段不存在则使用 missing 指定的缺省值。•modifier : 计算函数,为了避免分数相差过大,用于平滑分数,可以是以下之一:•none : 不处理,默认•log : log(factor * field_value)•log1p : log(1 + factor * field_value)•log2p : log(2 + factor * field_value)•ln : ln(factor * field_value)•ln1p : ln(1 + factor * field_value)•ln2p : ln(2 + factor * field_value)•square : 平方,(factor * field_value)^2•sqrt : 开方,sqrt(factor * field_value)•reciprocal : 求倒数,1/(factor * field_value)
假设某个匹配的文档的点赞数是 1000 ,那么例子中其打分函数生成的分数就是 log(1 + 1.2 * 1000),最终的分数是原来的 query 分数与此打分函数分数相差的结果。
decay_function
decay_function 衰减函数,例如:
•以某个数值作为中心点,距离多少的范围之外逐渐衰减(缩小分数)•以某个日期作为中心点,距离多久的范围之外逐渐衰减(缩小分数)•以某个地理位置点作为中心点,方圆多少距离之外逐渐衰减(缩小分数)
示例:
"DECAY_FUNCTION": { "FIELD_NAME": { "origin": "30, 120", "scale": "2km", "offset": "0km", "decay": 0.33 } }
上例的意思就是在距中心点方圆 2 公里之外,分数减少到三分之一(乘以 decay 的值 0.33)。
•DECAY_FUNCTION 可以是以下任意一种函数:
•linear : 线性函数
•exp : 指数函数
•gauss : 高斯函数
•origin : 中心点,只能是数值、日期、geo-point
•scale : 定义到中心点的距离
•offset : 偏移量,默认 0
•decay : 衰减指数,默认是 0.5
示例:
GET /_search { "query": { "function_score": { "gauss": { "@timestamp": { "origin": "2013-09-17", "scale": "10d", "offset": "5d", "decay": 0.5 } } } } }
中心点是 2013-09-17 日期,scale 是 10d 意味着日期范围是 2013-09-12 到 2013-09-22 的文档分数权重是 1 ,日期在 scale + offset = 15d 之外的文档权重是 0.5 。
如果参与计算的字段有多个值,默认选择最靠近中心点的值,也就是离中心点的最近距离,可以通过 multi_value_mode 设置:
•min : 最近距离
•max : 最远距离
•avg : 平均距离
•sum : 所有距离累加
示例:
GET /_search { "query": { "function_score": { "query": { "match": { "properties": "大阳台" } }, "functions": [ { "gauss": { "price": { "origin": "0", "scale": "2000" } } }, { "gauss": { "location": { "origin": "30, 120", "scale": "2km" } } } ], "score_mode": "multiply" } } }
假设这是搜索大阳台的房源,上例设置了 price 价格字段的中心点是 0 ,范围 2000 以内,以及 location 地理位置字段的中心点是 "30, 120" ,方圆 2km 之内,在这个范围之外的匹配结果的 score 分数会进行高斯衰减,即打分降低。
script_score
script_score 自定义脚本打分,如果上面的打分函数都满足不了你,你还可以直接编写脚本打分。
示例:
GET /_search { "query": { "function_score": { "query": { "match": { "message": "elasticsearch" } }, "script_score": { "script": { "source": "Math.log(2 + doc['my-int'].value)" } } } } }
在脚本中通过 doc['field'] 的形式去引用字段,doc['field'].value 就是使用字段值。
你也可以把额外的参数与脚本内容分开:
GET /_search { "query": { "function_score": { "query": { "match": { "message": "elasticsearch" } }, "script_score": { "script": { "params": { "a": 5, "b": 1.2 }, "source": "params.a / Math.pow(params.b, doc['my-int'].value)" } } } } }
结语
通过了解 Elasticsearch 的自定义打分相信你能更好的完成符合业务的综合性搜索。