Search code examples
elasticsearchelasticsearch-painless

Elasticsearch: Use loop in Painless script


I have an old version of Elasticsearch (5.6.16) on a production environment that I can't upgrade.

I'm trying to use a loop in a painless script_score script but I always face a runtime error.

All my documents can have one or several "badges", here the mapping:

"myDocument":{
    "properties":{
        "badges":{
            "type":"nested",
            "properties":{
                "name":{
                    "type":"keyword"
                }
            }
        },
    }
},

My goal is to do a custom script that will provide a better score for documents with a specific type of badge

So I made this script

for (item in doc['badges']) {
    if (item['name'] == "myCustomBadge") {
        return _score * 10000;
    }
}
return _score;

But unfortunately, I'm getting errors while I try to use it

{
    "query":{
        "function_score":{
            "query":{
                "match_all": {}
            },
            "functions":[
                {
                    "script_score":{
                        "script":{
                            "inline":"for (item in doc['badges']) { if (item['name'] == \"myCustomBadge\") { return _score * 10000; }}return _score;",
                            "lang":"painless"
                        }
                    }
                },
            ]
        }
    }
}

    "error":{
        "root_cause":[
            {
                "type":"script_exception",
                "reason":"runtime error",
                "script_stack":[
                    "org.elasticsearch.search.lookup.LeafDocLookup.get(LeafDocLookup.java:77)",
                    "org.elasticsearch.search.lookup.LeafDocLookup.get(LeafDocLookup.java:36)",
                    "for (item in doc['badges']) { ",
                    " ^---- HERE"
                ],
                "script":"for (item in doc['badges']) { if (item['name'] == \"myCustomBadge\") { return _score * 10000; }}return _score;",
                "lang":"painless"
            }
        ],
        "type":"search_phase_execution_exception",
        "reason":"all shards failed"
    }


I tried to change the for with an other variant, but same error.

    for(int i = 0; i < doc['badges']; i++) {
        if (doc['badges'][i]['name'] == "uaWorker") {
            return _score * 10000;
        }
    }
    return _score;

Could you help me find what I did wrong? Thanks you all


Solution

  • The problem is not the loop but the fact that badges is nested and you're trying to access it from doc values. In this case, you need to access the array of badges from the _source document directly, like this:

    for (item in params._source['badges'])