Search code examples
elasticsearchelasticsearch-painless

Elasticsearch painless returns wrong long values


Elasticsearch returns the rounded value when I try to get millis from the timestamp (using docker.elastic.co/elasticsearch/elasticsearch:7.11.0 image).

My mappings:

{
    "mappings": {
        "properties": {
         ...
            "updated_at": {
                "type": "date"
            }
         ...
        }
    }
}

My script query:

{
    "query": {
        "script_score": {
            "query": {
                "match_all": {}
            },
            "script": {
                "source": "doc['updated_at'].value.millis"
            }
        }
    }
}

Results:

{
    ...
    "hits": {
        ...
        "max_score": 1616185130000,
        "hits": [
            {
                ...
                "_score": 1616185130000,    <---- wrong value
                "_source": {
                    ...
                    "updated_at": 1616185148409    <---- should be this
                }
            },
            {
                ...
                "_score": 1616185130000,    <---- same wrong value even if updated_at is different
                "_source": {
                    ...
                    "updated_at": 1616185148408    <---- should be this
                }
            }
            ...

Also tried with long type in mappings:

{
    "mappings": {
        "properties": {
         ...
            "updated_at": {
                "type": "long"
            }
         ...
        }
    }
}

Query:

{
    "query": {
        "script_score": {
            "query": {
                "match_all": {}
            },
            "script": {
                "source": "doc['updated_at'].value"
            }
        }
    }
}

And got the same results.

I can't use sorting because we need boost by formula and I stuck with this issue.


Solution

  • The reason is because the _score of each document is of type float.

    A long value in Java has 64 bits precision while a float has 32 bits precision, so trying to fit a long into a float will make you lose some precision.

    Try this:

    long test = 1616185148409L;
    System.out.println("Value as long: " + value);
    System.out.println("Value as float: " + (float)value);
    

    Results:

    Value as long: 1616185148409
    Value as float: 1.61618513E12
    

    Which is consistent with what you're seeing.