三人行必有我师

ES脚本中有对象创建导致的性能慢

Elasticsearch | 作者 hufuman | 发布于2022年04月15日 | 阅读数:1840

我们在做多语言的内容搜索,其中有个场景是按照价格排序,说到价格就有个汇率的问题。
 
例如我们有如下索引:
{
    "price": {
        "type": "float"
    },
    "currency": {
        "type": "keyword"
    }
}
 
有两种实现这个需求的方法:
  1. 在创建索引的时候,把价格和汇率一起转化成rmbPrice,这样排序就可以用rmbPrice这个字段进行排序。这个方法的问题是:
    • 汇率是不断波动的,我们的用户对汇率波动比较敏感
    • 排序的时候按索引中的价格,显示价格时使用最新的汇率计算当时的价格,这两个价格的来源不一致会导致可能出现排序不正确
    • 如果汇率发生波动,就更新所有文档,会造成大量的文档变化,对集群压力比较大
  2. 使用脚本,排序的时候实时计算汇率。这个方法的问题是:
    • 排序的性能,和脚本复杂度相关,见下文:

 
有如下排序脚本:
def currencyMap=['CHF':6.9839,'FJD':3.15088,'MXN':0.3629,'SCR':0.4529,'CLP':0.01007,'UGX':0.0023,'ZAR':0.4942,'TND':3.4075,'TZS':0.0036,'VND':3.0E-4,'AUD':4.8388,'GYD':0.0294,'KPW':0.0068,'BOB':0.8929,'KHR':0.001,'IDR':4.9E-4,'SDG':0.0,'TRY':1.2041,'JOD':9.6765,'CUP':6.1393,'NT$':0.2216,'AED':1.8725,'HKD':0.8788,'RWF':0.0089,'RSD':0.066,'EUR':7.7437,'DOP':0.1408,'DKK':1.037,'CAD':5.2768,'MYR':1.674,'MMK':0.0044,'MUR':0.1995,'NOK':0.805,'RON':1.59078,'UYU':0.2518,'MAD':0.69757,'LKR':0.03765,'AZN':4.0708,'CRC':0.01105,'CZK':0.29423,'OMR':17.48161,'PGK':1.9941,'PKR':0.04311,'KES':0.0687,'SEK':0.7349,'BTN':0.10042,'BHD':17.85257,'ARS':0.1584,'QAR':1.84042,'KZT':0.01796,'SAR':1.8338,'IRR':1.7E-4,'MVR':0.3983,'INR':0.09602,'THB':0.2226,'XPF':0.0655,'KRW':0.00583,'NPR':0.0619,'JPY':0.06375,'MNT':0.0033,'PLN':1.8167,'GBP':8.6123,'HUF':0.0238,'KWD':22.12935,'PHP':0.13473,'BYR':3.3E-4,'RUB':0.1098,'PYG':0.00134,'ISK':0.05538,'JMD':0.0534,'COP':0.00214,'MGA':0.002,'RMB':1.0,'USD':6.8778,'BAM':4.0,'EGP':0.3859,'MOP':0.8532,'NAD':0.4829,'SGD':5.0706,'ETB':0.3064,'NIO':0.233,'LAK':8.0E-4,'PEN':2.11,'BND':4.94865,'NIS':1.643,'NZD':4.6201,'BRL':1.8384];
def price = doc['price'].value;
if (price == null) {
price = 0;
}
def currency = doc['currency'].value;
def exChangeRate = 1;
if (currency != null && currency != 'RMB' && currencyMap.get(currency) != null) {
exChangeRate = currencyMap.get(currency);
}
return price * exChangeRate;

经过测试,10W级别的数据,currencyMap中的元素个数,在1个和多个的情况下,性能差距非常明显。
 
 
请问有什么既不需要大量更新文档,也能实现比较快的汇率更新的方法吗?
 
先谢谢大家了。
 
 
已邀请:

Ombres

赞同来自: hufuman

currencyMap写到params里面,只会创建一次对象
  "script": {
        "source": " def currencyMap=params.currencyMap",
        "params": {
          "currencyMap": {}
        }
      }

要回复问题请先登录注册