How to use lambda expression in Painless?


(Kyle Lahnakoski) #1

I am attempting to define-and-call a lambda function. This technique works in Java, but I have not been able to do this from Painless:

{
    "from": 0,
    "query": {"bool": {"must": [{"match_all": {}}]}},
    "script_fields": {"v": {"script": {
        "inline": "((doc[\"v.$string\"].empty) && (doc[\"v.$number\"].empty))?null:((!(doc[\"v.$number\"].empty)) ? (((Function) (\n                        value -> {\n                            String output = String.valueOf(value);\n                            if (output.endsWith(\".0\")) {\n                                output = output.substring(0, output.length() - 2);\n                            }//endif\n                            return output;\n                        }\n                )).apply((doc[\"v.$number\"].values)[0])) : ((doc[\"v.$string\"].values)[0]))",
        "lang": "painless"
    }}},
    "size": 10,
    "stored_fields": []
}

here is a the same script, slightly better formatted,

((doc["v.$string"].empty) && (doc["v.$number"].empty))?null:((!(doc["v.$number"].empty)) ? (((Function) (
                    value -> {
                        String output = String.valueOf(value);
                        if (output.endsWith(".0")) {
                            output = output.substring(0, output.length() - 2);
                        }//endif
                        return output;
                    }
            )).apply((doc["v.$number"].values)[0])) : ((doc["v.$string"].values)[0]))

The query results in an error:

Internal Server Error:{
"error":{
	"root_cause":[{
		"type":"script_exception",
		"reason":"compile error",
		"script_stack":[
			"...                    value -> {\n                     ...",
			"                             ^---- HERE"
		],
		"script":"((doc[\"v.$string\"].empty) && (doc[\"v.$number\"].empty))?null:((!(doc[\"v.$number\"].empty)) ? (((Function) (\n                        value -> {\n                            String output = String.valueOf(value);\n                            if (output.endsWith(\".0\")) {\n                                output = output.substring(0, output.length() - 2);\n                            }//endif\n                            return output;\n                        }\n                )).apply((doc[\"v.$number\"].values)[0])) : ((doc[\"v.$string\"].values)[0]))",
		"lang":"painless"
	}],
	"type":"search_phase_execution_exception",
	"reason":"all shards failed",
	"phase":"query",
	"grouped":true,
	"failed_shards":[{
		"shard":0,
		"index":"testing_000_k20171012_153014",
		"node":"QAI8rNAFTsOpaRaSYAA1Hw",
		"reason":{
			"type":"script_exception",
			"reason":"compile error",
			"script_stack":[
				"...                    value -> {\n                     ...",
				"                             ^---- HERE"
			],
			"script":"((doc[\"v.$string\"].empty) && (doc[\"v.$number\"].empty))?null:((!(doc[\"v.$number\"].empty)) ? (((Function) (\n                        value -> {\n                            String output = String.valueOf(value);\n                            if (output.endsWith(\".0\")) {\n                                output = output.substring(0, output.length() - 2);\n                            }//endif\n                            return output;\n                        }\n                )).apply((doc[\"v.$number\"].values)[0])) : ((doc[\"v.$string\"].values)[0]))",
			"lang":"painless",
			"caused_by":{
				"type":"illegal_argument_exception",
				"reason":"invalid sequence of tokens near ['->'].",
				"caused_by":{"type":"no_viable_alt_exception","reason":null}
			}
		}
	}]
},
"status":500

}

I have tried a variety of legitimate Java, but nothing works. I suspect the Painless parser is expecting the lambda definition to be a parameter of a method call, not some stand-alone entity. How can I call this lambda expression?

Thank you


Painless Lambda expressions
(Kyle Lahnakoski) #2

The trick is to find a method that accepts a lambda. In this case Optional.of(<expr>).map(<lambda>).orElse(null) works good enough:

{
    "from": 0,
    "query": {"bool": {"must": [{"match_all": {}}]}},
    "script_fields": {"v": {"script": {
        "inline": "((doc[\"v.$string\"].empty) && (doc[\"v.$number\"].empty))?null:((!(doc[\"v.$number\"].empty)) ? (Optional.of((doc[\"v.$number\"].values)[0]).map(\n                        value -> {\n                            String output = String.valueOf(value);\n                            if (output.endsWith(\".0\")) {\n                                output = output.substring(0, output.length() - 2);\n                            }//endif\n                            return output;\n                        }\n                ).orElse(null)) : ((doc[\"v.$string\"].values)[0]))",
        "lang": "painless"
    }}},
    "size": 10,
    "stored_fields": []
}

(system) #3

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.