在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
,例如1
和2
,术语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。
所以我的问题是:
- 2219658752有什么特别之处呢?我知道32位浮点数的上限是(2-2^-23)× 2^127,这比2219658785高得多,不是吗?
1.我可以使用term
查询来定位cid
,还是必须使用long
或double
重新索引?
1条答案
按热度按时间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将无法看到这些数字之间的差异。