Elastic Search 排序预处理
Elastic Search sort preprocessing
我在 ES 中有一个索引,除了其他字段外,还有 revenue_amount 和 revenue_currency 字段。收入以不同的货币存储。在 运行 时,所有货币都转换为美元并呈现。
现在,我想支持对 revenue_amount 字段进行排序。问题是 ES 在转换为美元之前根据收入对结果进行排序,因此在顶部返回的收入可能不是转换为美元后的最高收入。
我在想,有没有可能在排序之前,ES先调用一个用户定义的函数,改变一个字段值,然后再进行排序?像这样:
revenue_converted = convertToUSD(revenue)
因此排序将应用于 revenue_converted,而不是收入。
我知道我可以在索引时间转换货币,但是每次更新汇率时都需要刷新索引,所以我想尽可能避免它。
您有两种方法可以实现此目的:一种是使用 script-based sorting 作为基蒂提到的:
{
"query" : {
.... <--- your query goes here
},
"sort" : {
"_script" : {
"script" : "doc.revenue_amount.value * usd_conversion_rate",
"type" : "number",
"params" : {
"usd_conversion_rate" : 0.4273 <--- the conversion rate to USD
},
"order" : "desc"
}
}
}
usd_conversion_rate
因素是美元的兑换率。因此,例如,如果 1 美元价值 2.34 个单位的另一种货币,则 usd_conversion_rate
系数将为 1 / 2.34
(或 0.4273
)。当与 revenue_amount
相乘时,它会给你美元参考货币的金额。
不过,基于脚本的排序效率不高,建议使用 function_score
,这样结果可以按分数排序。这导致我们采用第二种方式来实现您的需求,它是这样的。一种方法是使用 script_score
函数,但这涉及再次编写脚本。
{
"query": {
"function_score": {
"query": {},
"functions": [
{
"script_score": {
"script": "doc.revenue_amount.value * usd_conversion_rate",
"boost_mode": "replace",
"params": {
"usd_conversion_rate": 0.4273
}
}
}
]
}
}
}
由于我们上面的脚本非常简单(即,将一个字段乘以某个因子),最简单的方法是使用 field_value_factor
,它是这样的:
{
"query": {
"function_score": {
"query": {
... <--- your query goes here
},
"functions": [
{
"field_value_factor": {
"field": "revenue_amount",
"boost_mode": "replace",
"factor": 0.4273 <--- insert the conversion rate here
}
}
]
}
}
}
更新
根据您的最新评论,看来您的正确选择毕竟是使用 script_score
。这里的想法是输入查找 table 中可用的所有货币汇率作为 script_score
脚本的参数,然后根据 revenue_currency
字段的值使用正确的汇率。
{
"query": {
"function_score": {
"query": {},
"functions": [
{
"script_score": {
"script": "doc.revenue_amount.value * (doc.revenue_currency.value == 'EUR' ? EUR : (doc.revenue_currency.value == 'AUD' ? AUD : 1))",
"boost_mode": "replace",
"params": {
"EUR": 0.4945,
"AUD": 0.5623
}
}
}
]
}
}
}
我在 ES 中有一个索引,除了其他字段外,还有 revenue_amount 和 revenue_currency 字段。收入以不同的货币存储。在 运行 时,所有货币都转换为美元并呈现。
现在,我想支持对 revenue_amount 字段进行排序。问题是 ES 在转换为美元之前根据收入对结果进行排序,因此在顶部返回的收入可能不是转换为美元后的最高收入。
我在想,有没有可能在排序之前,ES先调用一个用户定义的函数,改变一个字段值,然后再进行排序?像这样:
revenue_converted = convertToUSD(revenue)
因此排序将应用于 revenue_converted,而不是收入。
我知道我可以在索引时间转换货币,但是每次更新汇率时都需要刷新索引,所以我想尽可能避免它。
您有两种方法可以实现此目的:一种是使用 script-based sorting 作为基蒂提到的:
{
"query" : {
.... <--- your query goes here
},
"sort" : {
"_script" : {
"script" : "doc.revenue_amount.value * usd_conversion_rate",
"type" : "number",
"params" : {
"usd_conversion_rate" : 0.4273 <--- the conversion rate to USD
},
"order" : "desc"
}
}
}
usd_conversion_rate
因素是美元的兑换率。因此,例如,如果 1 美元价值 2.34 个单位的另一种货币,则 usd_conversion_rate
系数将为 1 / 2.34
(或 0.4273
)。当与 revenue_amount
相乘时,它会给你美元参考货币的金额。
不过,基于脚本的排序效率不高,建议使用 function_score
,这样结果可以按分数排序。这导致我们采用第二种方式来实现您的需求,它是这样的。一种方法是使用 script_score
函数,但这涉及再次编写脚本。
{
"query": {
"function_score": {
"query": {},
"functions": [
{
"script_score": {
"script": "doc.revenue_amount.value * usd_conversion_rate",
"boost_mode": "replace",
"params": {
"usd_conversion_rate": 0.4273
}
}
}
]
}
}
}
由于我们上面的脚本非常简单(即,将一个字段乘以某个因子),最简单的方法是使用 field_value_factor
,它是这样的:
{
"query": {
"function_score": {
"query": {
... <--- your query goes here
},
"functions": [
{
"field_value_factor": {
"field": "revenue_amount",
"boost_mode": "replace",
"factor": 0.4273 <--- insert the conversion rate here
}
}
]
}
}
}
更新
根据您的最新评论,看来您的正确选择毕竟是使用 script_score
。这里的想法是输入查找 table 中可用的所有货币汇率作为 script_score
脚本的参数,然后根据 revenue_currency
字段的值使用正确的汇率。
{
"query": {
"function_score": {
"query": {},
"functions": [
{
"script_score": {
"script": "doc.revenue_amount.value * (doc.revenue_currency.value == 'EUR' ? EUR : (doc.revenue_currency.value == 'AUD' ? AUD : 1))",
"boost_mode": "replace",
"params": {
"EUR": 0.4945,
"AUD": 0.5623
}
}
}
]
}
}
}