TL;DR
I'm trying to pass in a nested key to a Painless script as a string and set that key from the script, but it's not working. How do I do this?# Use Case
Long Version
Use Case
As a user, I need to perform the same transform in an ingest pipeline using a Painless script on multiple nested fields. However, the field name is arbitrary and will vary, based on the input data.
Current Solution
The best solution appears to be to pass the name of the nested field into the script as a string (e.g., a.b.c
), but this does not work in all situations.
Example
Assume the following document structure:
{
"a": {
"b": {
"c": "string"
}
}
}
Applying the following script to retrieve the value of a.b.c
works as expected with the parameter { "source_field": "a.b.c" }
:
def val = ctx;
def keys = params['source_field'].splitOnToken('.');
for (key in keys) {
val = val[key];
}
val;
I don't like having to iterate down through the object to get the value for a.b.c
, but it works.
If I execute the following code with the parameters { "source_field": "a.b.c", "dest_field": "d.e.f" }
:
def val = ctx;
def keys = params['source_field'].splitOnToken('.');
for (key in keys) {
val = val[key];
}
ctx[params['dest_field']] = val;
I get the expected output:
{
"a": {
"b": {
"c": "string"
}
},
"d": {
"e": {
"f": "string"
}
}
}
However, if d.e.f
already exists and I'm attempting to overwrite the field, or even d
exists, it does not save d.e.f
to the document. Presumably this is because what I'm actually doing is creating a new key called {"d.e.f":"string"}
.
How can I accomplish this?
Note: It would be great if the
set
ingest processor were exposed through theProcessors
object, but alas, it's not.