排名特征
使用 rank_feature 查询可以根据文档中的数值(例如相关性分数、流行度或新鲜度)提升文档分数。此查询非常适合需要使用数值特征微调相关性排名的场景。与 全文查询 不同,rank_feature 仅关注数值信号;当与 bool 等复合查询结合使用时,它最有效。
为了使 rank_feature 查询生效,目标字段需要被映射为 rank_feature 字段类型。这可以实现内部优化的评分,从而实现快速高效的提升。
分数影响取决于字段值和可选的 saturation、log 或 sigmoid 函数。这些函数在查询时动态应用以计算最终文档分数;它们不会更改或存储文档本身的任何值。
参数
rank_feature 查询支持以下参数。
| 参数 | 数据类型 | 必需/可选 | 描述 |
|---|---|---|---|
field | 字符串 | 必需 | 一个 rank_feature 或 rank_features 字段,用于对文档评分。 |
提升 | 浮点型 | 可选 | 应用于分数的乘数。默认值为 1.0。介于 0 和 1 之间的值会降低分数;大于 1 的值会放大分数。 |
saturation | 对象 | 可选 | 对特征值应用饱和函数。提升随值增长,但在超出 pivot 后趋于平稳。如果未提供其他函数,则为默认函数。每次只能使用 saturation、log 或 sigmoid 中的一个函数。 |
log | 对象 | 可选 | 使用基于字段值的对数评分函数。最适合大范围值。每次只能使用 saturation、log 或 sigmoid 中的一个函数。 |
sigmoid | 对象 | 可选 | 应用由 pivot 和 exponent 控制的 Sigmoid(S 形)曲线来影响分数。每次只能使用 saturation、log 或 sigmoid 中的一个函数。 |
positive_score_impact | 布尔型 | 可选 | 当设置为 false 时,较低的值得分更高。适用于价格等特征,其中较小的值更好。在映射中定义。默认值为 true。 |
示例
以下示例演示如何定义和使用 rank_feature 字段来影响文档评分。
创建具有排序特征字段的索引
定义一个具有 rank_feature 字段的索引,以表示像 popularity 这样的信号
PUT /products
{
"mappings": {
"properties": {
"title": { "type": "text" },
"popularity": { "type": "rank_feature" }
}
}
}
索引示例文档
添加具有不同流行度值的示例产品
POST /products/_bulk
{ "index": { "_id": 1 } }
{ "title": "Wireless Earbuds", "popularity": 1 }
{ "index": { "_id": 2 } }
{ "title": "Bluetooth Speaker", "popularity": 10 }
{ "index": { "_id": 3 } }
{ "title": "Portable Charger", "popularity": 25 }
{ "index": { "_id": 4 } }
{ "title": "Smartwatch", "popularity": 50 }
{ "index": { "_id": 5 } }
{ "title": "Noise Cancelling Headphones", "popularity": 100 }
{ "index": { "_id": 6 } }
{ "title": "Gaming Laptop", "popularity": 250 }
{ "index": { "_id": 7 } }
{ "title": "4K Monitor", "popularity": 500 }
基本排序特征查询
您可以使用 rank_feature 根据 popularity 分数提升结果
POST /products/_search
{
"query": {
"rank_feature": {
"field": "popularity"
}
}
}
此查询本身不执行过滤。相反,它根据 popularity 的值对所有文档进行评分。值越高,分数越高。
{
...
"hits": {
"total": {
"value": 7,
"relation": "eq"
},
"max_score": 0.9252834,
"hits": [
{
"_index": "products",
"_id": "7",
"_score": 0.9252834,
"_source": {
"title": "4K Monitor",
"popularity": 500
}
},
{
"_index": "products",
"_id": "6",
"_score": 0.86095566,
"_source": {
"title": "Gaming Laptop",
"popularity": 250
}
},
{
"_index": "products",
"_id": "5",
"_score": 0.71237755,
"_source": {
"title": "Noise Cancelling Headphones",
"popularity": 100
}
},
{
"_index": "products",
"_id": "4",
"_score": 0.5532503,
"_source": {
"title": "Smartwatch",
"popularity": 50
}
},
{
"_index": "products",
"_id": "3",
"_score": 0.38240916,
"_source": {
"title": "Portable Charger",
"popularity": 25
}
},
{
"_index": "products",
"_id": "2",
"_score": 0.19851118,
"_source": {
"title": "Bluetooth Speaker",
"popularity": 10
}
},
{
"_index": "products",
"_id": "1",
"_score": 0.024169207,
"_source": {
"title": "Wireless Earbuds",
"popularity": 1
}
}
]
}
}
与全文搜索结合
要过滤相关结果并根据流行度提升它们,请使用以下请求。此查询对所有匹配“headphones”的文档进行排名,并提升流行度更高的文档。
POST /products/_search
{
"query": {
"bool": {
"must": {
"match": {
"title": "headphones"
}
},
"should": {
"rank_feature": {
"field": "popularity"
}
}
}
}
}
Boost 参数
通过 boost 参数,您可以调整 rank_feature 子句的分数贡献。这在 bool 等复合查询中特别有用,您可以在其中控制数值字段(如流行度、新鲜度或相关性分数)对最终文档排名的影响程度。
在以下示例中,bool 查询匹配 title 中包含“headphones”一词的文档,并使用 rank_feature 子句和 2.0 的 boost 值来提升更受欢迎的结果。这将使 rank_feature 分数对文档总分的贡献翻倍。
POST /products/_search
{
"query": {
"bool": {
"must": {
"match": {
"title": "headphones"
}
},
"should": {
"rank_feature": {
"field": "popularity",
"boost": 2.0
}
}
}
}
}
配置评分函数
默认情况下,rank_feature 查询使用从字段派生的 pivot 值和 saturation 函数。您可以显式地将函数设置为 saturation、log 或 sigmoid。
饱和函数
在 rank_feature 查询中,saturation 函数是默认的评分方法。它为具有较大特征值的文档分配更高的分数,但随着值超过指定的 pivot,分数的增长会变得更加平缓。当您希望对非常大的值给予递减的回报时,这很有用,例如,在提升 popularity 的同时避免过度奖励极高的数字。计算分数的公式是 rank_feature 字段的值 / (rank_feature 字段的值 + pivot)。生成的分数始终在 0 到 1 之间。如果未提供 pivot,则使用索引中所有 rank_feature 值的近似几何平均值。
以下示例使用 saturation,pivot 值为 50。
POST /products/_search
{
"query": {
"rank_feature": {
"field": "popularity",
"saturation": {
"pivot": 50
}
}
}
}
pivot 定义了评分增长放缓的点。高于 pivot 的值仍然会增加分数,但回报会递减,如返回的命中所示。
{
...
"hits": {
"total": {
"value": 7,
"relation": "eq"
},
"max_score": 0.9090909,
"hits": [
{
"_index": "products",
"_id": "7",
"_score": 0.9090909,
"_source": {
"title": "4K Monitor",
"popularity": 500
}
},
{
"_index": "products",
"_id": "6",
"_score": 0.8333333,
"_source": {
"title": "Gaming Laptop",
"popularity": 250
}
},
{
"_index": "products",
"_id": "5",
"_score": 0.6666666,
"_source": {
"title": "Noise Cancelling Headphones",
"popularity": 100
}
},
{
"_index": "products",
"_id": "4",
"_score": 0.5,
"_source": {
"title": "Smartwatch",
"popularity": 50
}
},
{
"_index": "products",
"_id": "3",
"_score": 0.3333333,
"_source": {
"title": "Portable Charger",
"popularity": 25
}
},
{
"_index": "products",
"_id": "2",
"_score": 0.16666669,
"_source": {
"title": "Bluetooth Speaker",
"popularity": 10
}
},
{
"_index": "products",
"_id": "1",
"_score": 0.019607842,
"_source": {
"title": "Wireless Earbuds",
"popularity": 1
}
}
]
}
}
对数函数
当 rank_feature 字段包含大量值范围时,log 函数很有用。它对 score 应用对数刻度,从而减少极高值的影响,并有助于在广泛的值分布中规范化评分。当低值之间的微小差异应比高值之间的较大差异更具影响力时,这尤其有用。分数使用公式 log(scaling_factor + rank_feature field) 计算。以下示例使用 scaling_factor 为 2
POST /products/_search
{
"query": {
"rank_feature": {
"field": "popularity",
"log": {
"scaling_factor": 2
}
}
}
}
在示例数据集中,popularity 字段的范围是 1 到 500。log 函数会压缩 250 和 500 等大值对 score 的贡献,同时仍允许值为 10 或 25 的文档获得有意义的分数。相比之下,如果应用 saturation 函数,高于 pivot 的文档将迅速接近相同的最大分数
{
...
"hits": {
"total": {
"value": 7,
"relation": "eq"
},
"max_score": 6.2186003,
"hits": [
{
"_index": "products",
"_id": "7",
"_score": 6.2186003,
"_source": {
"title": "4K Monitor",
"popularity": 500
}
},
{
"_index": "products",
"_id": "6",
"_score": 5.529429,
"_source": {
"title": "Gaming Laptop",
"popularity": 250
}
},
{
"_index": "products",
"_id": "5",
"_score": 4.624973,
"_source": {
"title": "Noise Cancelling Headphones",
"popularity": 100
}
},
{
"_index": "products",
"_id": "4",
"_score": 3.9512436,
"_source": {
"title": "Smartwatch",
"popularity": 50
}
},
{
"_index": "products",
"_id": "3",
"_score": 3.295837,
"_source": {
"title": "Portable Charger",
"popularity": 25
}
},
{
"_index": "products",
"_id": "2",
"_score": 2.4849067,
"_source": {
"title": "Bluetooth Speaker",
"popularity": 10
}
},
{
"_index": "products",
"_id": "1",
"_score": 1.0986123,
"_source": {
"title": "Wireless Earbuds",
"popularity": 1
}
}
]
}
}
Sigmoid 函数
sigmoid 函数提供平滑的 S 形评分曲线,这在您希望控制评分影响的陡峭度和中点时特别有用。分数使用公式 rank feature field value^exp / (rank feature field value^exp + pivot^exp) 得出。以下示例使用配置了 pivot 和 exponent 的 sigmoid 函数。pivot 定义了分数为 0.5 的值。exponent 控制曲线的陡峭程度。值越低,在 pivot 附近的过渡越急剧
POST /products/_search
{
"query": {
"rank_feature": {
"field": "popularity",
"sigmoid": {
"pivot": 50,
"exponent": 0.5
}
}
}
}
sigmoid 函数平滑地提升 pivot 附近(在此示例中为 50)的分数,对接近 pivot 的值给予适度偏好,同时使高低极端值趋于平缓
{
...
"hits": {
"total": {
"value": 7,
"relation": "eq"
},
"max_score": 0.7597469,
"hits": [
{
"_index": "products",
"_id": "7",
"_score": 0.7597469,
"_source": {
"title": "4K Monitor",
"popularity": 500
}
},
{
"_index": "products",
"_id": "6",
"_score": 0.690983,
"_source": {
"title": "Gaming Laptop",
"popularity": 250
}
},
{
"_index": "products",
"_id": "5",
"_score": 0.58578646,
"_source": {
"title": "Noise Cancelling Headphones",
"popularity": 100
}
},
{
"_index": "products",
"_id": "4",
"_score": 0.5,
"_source": {
"title": "Smartwatch",
"popularity": 50
}
},
{
"_index": "products",
"_id": "3",
"_score": 0.41421357,
"_source": {
"title": "Portable Charger",
"popularity": 25
}
},
{
"_index": "products",
"_id": "2",
"_score": 0.309017,
"_source": {
"title": "Bluetooth Speaker",
"popularity": 10
}
},
{
"_index": "products",
"_id": "1",
"_score": 0.12389934,
"_source": {
"title": "Wireless Earbuds",
"popularity": 1
}
}
]
}
}
反转分数影响
默认情况下,值越高分数越高。如果您希望较低的值产生较高的分数(例如,较低的价格更相关),请在索引创建期间将 positive_score_impact 设置为 false
PUT /products_new
{
"mappings": {
"properties": {
"popularity": {
"type": "rank_feature",
"positive_score_impact": false
}
}
}
}