Cannot apply [>] operation to types [ScriptDocValues.Doubles] and [java.lang.Integer]

文章讲述了在使用Elasticsearch的脚本指标统计时遇到的类型转换异常,原因是balance字段的ScriptDocValues.Doubles类型不支持直接比较。解决方法是通过getValue()获取原始值进行比较。

在使用elasticsearch脚本指标统计时,出现了异常:
脚本:

POST account_test/_search?size=0
{
  "query": {
    "match_all": {}
  },
  "aggs": {
    "balance_positive_sum": {
      "scripted_metric": {
        "init_script": "state.balances=[]",
        "map_script": "if(doc.balance > 0){state.balances.add( doc.balance)}",
        "combine_script": "double balanceSum=0;for(num in state.balances){balanceSum+=num} return balanceSum ",
        "reduce_script": "double balanceSum=0;for(num in states){balanceSum+=num} return balanceSum"
      }
    }
  }
}

异常:

{
  "error": {
    "root_cause": [
      {
        "type": "class_cast_exception",
        "reason": "class_cast_exception: Cannot apply [>] operation to types [org.elasticsearch.index.fielddata.ScriptDocValues.Doubles] and [java.lang.Integer]."
      }
    ],
    "type": "search_phase_execution_exception",
    "reason": "all shards failed",
    "phase": "query",
    "grouped": true,
    "failed_shards": [
      {
        "shard": 0,
        "index": "account_test",
        "node": "cdYh0ptNTP6kMXlVSE8dqA",
        "reason": {
          "type": "script_exception",
          "reason": "runtime error",
          "script_stack": [
            "if(doc.balance > 0){",
            "      ^---- HERE"
          ],
          "script": "if(doc.balance > 0){state.balances.add( doc.balance)}",
          "lang": "painless",
          "caused_by": {
            "type": "class_cast_exception",
            "reason": "class_cast_exception: Cannot apply [>] operation to types [org.elasticsearch.index.fielddata.ScriptDocValues.Doubles] and [java.lang.Integer]."
          }
        }
      }
    ],
    "caused_by": {
      "type": "class_cast_exception",
      "reason": "class_cast_exception: Cannot apply [>] operation to types [org.elasticsearch.index.fielddata.ScriptDocValues.Doubles] and [java.lang.Integer]."
    }
  },
  "status": 400
}

原因是在脚本中balance对应的类型是ScriptDocValues.Doubles,也就是封装类型,能直接执行>、<、=等操作,需要转原始类型。

解决办法:
调用getValue() 方法或者原始值。

POST account_test/_search?size=0
{
  "query": {
    "match_all": {}
  },
  "aggs": {
    "balance_positive_sum": {
      "scripted_metric": {
        "init_script": "state.balances=[]",
        "map_script": "if(doc.balance.getValue() > 0){state.balances.add( doc.balance.getValue())}",
        "combine_script": "double balanceSum=0;for(num in state.balances){balanceSum+=num} return balanceSum ",
        "reduce_script": "double balanceSum=0;for(num in states){balanceSum+=num} return balanceSum"
      }
    }
  }
}

更多方法参考:ScriptDocValues.Doubles Java Doc。

### 时间应以双精度浮点数表示的原因 在编程中,时间通常被表示为从某个固定参考点(例如 Unix 纪元)开始的流逝时间。这种表示方法可以采用整数或浮点数形式。然而,选择双精度浮点数作为时间的表示方式有以下几个关键原因: 1. **高精度需求**:某些应用场景需要非常高的时间精度,例如科学计算、金融交易系统或实时系统。双精度浮点数能够提供高达 15-17 位有效数字的精度[^2],这足以满足大多数高精度时间测量的需求。 2. **范围广泛**:双精度浮点数可以表示一个非常大的数值范围。对于时间戳而言,这意味着它可以轻松覆盖从远古时代到未来的任意时间点,而不会因为溢出问题导致错误。例如,使用双精度浮点数表示的时间戳可以覆盖从公元 0 年到数十亿年后的任意时间点[^1]。 3. **兼容性与标准化**:许多现代编程语言和库(如 C++ 的 `std::chrono` 或 Python 的 `datetime` 模块)支持将时间表示为双精度浮点数。这种表示方式已经成为行业标准之一,便于跨平台和跨语言的互操作性[^3]。 4. **灵活性**:双精度浮点数允许以不同的单位表示时间,例如秒、毫秒或纳秒。通过简单的数学运算,可以轻松地在不同时间单位之间进行转换。例如,将秒转换为毫秒只需乘以 1000,这在整数表示中可能会因溢出或精度损失而变得复杂[^2]。 以下是一个示例代码,展示如何使用双精度浮点数来表示和操作时间: ```cpp #include <iostream> #include <chrono> int main() { // 获取当前时间点,并将其转换为双精度浮点数表示的秒数 auto now = std::chrono::system_clock::now(); auto duration = now.time_since_epoch(); double timeInSeconds = std::chrono::duration_cast<std::chrono::duration<double>>(duration).count(); std::cout << "Current time in seconds since epoch: " << timeInSeconds << std::endl; return 0; } ``` ### 注意事项 尽管双精度浮点数提供了高精度和大范围的优点,但在某些情况下也可能引入舍入误差。因此,在对时间差进行精确计算时,需要特别注意这些潜在的误差[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冲上云霄的Jayden

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值