elasticsearch - Elasticsearch 排序预处理

标签 elasticsearch lucene

我在ES中有一个索引,除其他字段外,该索引还具有Revenue_amount和Revenue_currency字段。收入以不同的货币存储。在运行时,所有货币都将转换为USD并进行渲染。

现在,我想支持在Revenue_amount字段上进行排序。问题在于,ES在转换为美元之前会根据收入对结果进行排序,因此返回顶部的收入可能不是转换为美元后的最高收入。

我想知道,是否有可能在排序之前,ES调用用户定义的函数来更改字段值,然后再应用排序?像这样:

revenue_converted = convertToUSD(revenue)



因此,排序将应用于收入转换后的收入,而不是收入。

我知道我可以在索引时转换货币,但是这需要在每次更新汇率时刷新索引,因此,如果可能的话,我想避免这种情况。

最佳答案

您有两种方法可以实现此目的:一种是通过使用script-based sorting作为前面提到的keety:

{
    "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因素是USD的转换率。因此,例如,如果1美元值(value)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。这里的想法是在查询表中输入所有可用的货币汇率作为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
            }
          }
        }
      ]
    }
  }
}

关于elasticsearch - Elasticsearch 排序预处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32058673/

相关文章:

java - 使用 IntField 的 Lucene 搜索查询在文档更新后不起作用

azure 搜索完全匹配

python - 通过elasticsearch_dsl使用 “must_not exists”

ruby-on-rails - Searchkick建议支持3个字符的单词

elasticsearch - 使用ElasticSearch映射文档时出现问题

mysql - 使用 ElasticSearch 索引 MySQL 数据

lucene - 分页Lucene的搜索结果

elasticsearch - 使用 Kibana 6.0 或 7+ (v7.0.1) 从控制台创建索引模式

java - Lucene 通配符匹配在化学符号上失败(?)

elasticsearch - Logstash-仅解析一个JSON事件