Elasticsearch terms在32位浮点数上的查询行为奇怪

qnakjoqk  于 7个月前  发布在  ElasticSearch
关注(0)|答案(1)|浏览(78)

在Elasticsearch v6.8.5和v7.11.0中,我很难理解浮点数被转换为双精度浮点数并丢失精度的行为,从而破坏了我的term查询。
由于技术债务的原因,我有一个float类型的索引Map:

PUT test
{
  "mappings": {
    "properties": {
      "cid": {
        "type" : "float",
        "ignore_malformed": false,
        "coerce" : false
      }
    }
  }
}

字符串
为包含cid s 2219658785和2219658651的两个文档编制索引后:

POST test/_doc
{
  "cid": 2219658785
}

POST test/_doc
{
  "cid": 2219658651
}


并查询2219658785

GET test/_search
{
  "query": {
    "term": {
      "cid": {
        "value": 2219658785
      }
    }
  },
  "aggs": {
    "uniqueByCid": {
      "cardinality": {
        "field": "cid"
      }
    }
  }
}

*两个文档均已返回

  • 并且cid基数是1

很奇怪。“
如果我保留Map并索引更小的cid,例如12,术语query就能按预期工作-只返回1个文档。
因此,我认为我的大cid不适合float,并被转换为doubles,因为

GET test/_search
{
  "query": {
    "script": {
      "script": "Debug.explain(doc['cid']);"
    }
  }
}


打印输出ScriptDocValues.Doubles
为了进一步检查,我使用DecimalFormat运行了一个脚本:

GET test/_search
{
  "query": {
    "script": {
      "script": """
          DecimalFormat df = new DecimalFormat("#");
          
          def val = doc['cid'].value;
          
          Debug.explain([val, df.format(val)]);
      """
    }
  }
}


我看到:

{
  "error" : {
    "root_cause" : [
      {
        "type" : "script_exception",
        "reason" : "runtime error",
        "painless_class" : "java.util.ArrayList",
        "to_string" : "[2.219658752E9, 2219658752]",
                                       ^^^^^^^^^^


假设上面的文档包含cid: 2219658785,则Elasticsearch将2219658785转换为2219658752。但对于cid: 2219658651,脚本也会打印出2219658752!
显然,“铸造”float s(或者更确切地说,long s?)的上限似乎是2219658752。
所以我的问题是:

  1. 2219658752有什么特别之处呢?我知道32位浮点数的上限是(2-2^-23)× 2^127,这比2219658785高得多,不是吗?
    1.我可以使用term查询来定位cid,还是必须使用longdouble重新索引?
q5iwbnjs

q5iwbnjs1#

2219658752有什么特别之处呢?我知道32位浮点数的上限是(2-2^-23)× 2^127,这比2219658785高得多,不是吗?
你链接的表中重要的部分不是最大值,而是有效位/数字。如果你看看float is structured是如何。一旦你不能适应有效位,你就开始失去精度。所以,虽然它可以表示比你的数字高得多的数字,但在你达到16777216后,它开始失去精度。任何关于16,777的东西,217几个数字将被Map成一个值。
所以,为了回答你的问题,2,219,658,785没有什么特别之处。它只是不能在不失去精度的情况下放入浮点数。在这种情况下,你会失去不到3个小数点。所以基本上所有2,219,658,624和2,219,658之间的数字,880在elasticsearch中表示为相同的值,elasticsearch将无法看到这些数字之间的差异。

相关问题