Painless updates are not searchable

I am trying to do an updateByQuery with the javascript api, and am using painless. Before running updateByQuery, I first update the index's mapping by adding in the following:

await putMapping(elastic, index, {
      properties: {
        maps: {
          type: 'nested',
          properties: {
            ...Object.assign(
              {},
              ...maps.map((m) => ({
                [m.id]: {
                  type: 'text',
                  fields: {
                    raw: {
                      type: 'keyword',
                    },
                  },
                },
              }))
            ),
          },
        },
      },
    });

which basically says, allow documents to have a field called maps that will contain n number of fields, that will be a text / keyword type. So I'm expecting to have something like ctx._source.maps.A as a text or keyword type eventually.

Once the mapping is updated, I then want to leverage updateByQuery to update documents that are returned from various queries so that they have values in the _source.maps[mapId] space.

My painless script in the updateByQuery looks something like this:

if (!ctx._source.containsKey('maps')) {
    def m = new HashMap();
    ctx._source['maps'] = m;
  }
  if (!ctx._source.maps.containsKey('${mapId}')) {
    ctx._source.maps['${mapId}'] = new ArrayList();
  }
  if(!ctx._source.maps.${mapId}.contains('myKeywordIWantToAdd')){
    ctx._source.maps.${mapId}.add('myKeywordIWantToAdd');
  }

When I run this updateByQuery, and then run a search using the same query used in updateByQuery, and then look at the returned results, I can see that the _source is updated. However, those fields are not searchable. If I try to run an exists query on maps.A for example, nothing is returned. If I do an exists query on just maps nothing returns either. If I do a term search on maps.A for a value I KNOW exists in that list, nothing returns. I've tried refreshing and flushing the index with no luck.

My best guess is that I should not be using a HashMap or a ArrayList to build out new portions of my document, but I'm not really sure. Any guidance would be greatly appreciated. Thank you.

This painless script in combination with ${mapId} - which I suppose is some javascript expansion does make debugging really hard. Can you share a sample document plus the script the really gets sent to elasticsearch? This way others could locally reproduce your problem.

Hi Alexander,

Yes, I can share. And apologies, I meant to strip out the ${mapId} and replace with 'A'. The ${} is just for string templating in JS. Updated script is below, after the sample document

  1. Sample Document (I removed some of the data so as to not be crazy long):
    {
          "keywords" : [
            {
              "majorTopic" : "N",
              "keyword" : "torso"
            }
          ],
          "genes" : [ ],
          "language" : "eng",
          "abstract" : [
            {
              "label" : "",
              "text" : "The correction of adolescent scoliosis involves the recreation of torso symmetry. A symmetrical torso has equivalent areas of shape on either side of the midline. The posterior torso has two areas of prominence, known as the 'most prominent points' on either side of the midline which can be used as reference points to measure symmetry of the posterior torso. This study used the three-dimensional (3D) coordinates of the most prominent points, measured using ISIS2 surface topography and standardised by torso size, in children without abnormal surface topography, with adolescent idiopathic scoliosis (AIS) (right thoracic curves) and with Scheuermann's kyphosis (SK). The purpose was to demonstrate the variability of the position of the points in these three groups. The variability of the 3D coordinates was calculated for each group (mean, standard deviation and range in millimetres) and the standardised data were illustrated using 3D 95% confidence interval ellipsoids. In those without deformity, the position of the left and right point was mirrored with little difference. The AIS group showed a difference between the left and right points, with the right becoming further from the midline and more prominent than the left but with the left becoming more superior than the right. For the SK cohort, both left and right points moved inwards towards the midline and became more prominent. Linear mixed effect modelling was used to examine the contribution of age, kyphosis and scoliosis to the position of the most prominent points. In the cohort without abnormal surface topography, the x parameter increases with the covariates of age and kyphosis, with the covariate of age likely reflecting torso growth. The left side becomes more prominent and inferior compared to the right. In the AIS cohort, age follows the cohort without abnormal surface topography. This is added to by the scoliosis which is observed to make the right side more lateral, less inferior and more prominent, whereas the left becomes more medial, less inferior and less prominent. Kyphosis in the AIS cohort leads to the right point becoming more lateral, less inferior and less prominent whereas in the left becomes more lateral, more inferior and more prominent. In the SK cohort, the effects of the covariates of age and kyphosis are not clear reflecting the small number of cases with more than one surface topography image over time.",
              "category" : ""
            }
          ],
          "pmid" : 33305353,
          "title" : "The variability in location of the most prominent points on the posterior torso of those without abnormal surface topography, those with Adolescent Idiopathic Scoliosis and those with Scheuermann's Kyphosis: a seven year longitudinal analysis.",
          "journal" : {
            "country" : "England",
            "issn" : "1469-7580",
            "titleAbrv" : "J Anat",
            "nlmId" : "0137162",
            "title" : "Journal of anatomy",
            "publicationDate" : "2020-12-11"
          },
          "meshTags" : [ ],
          "abstractCopyright" : "© 2020 Anatomical Society.",
          "supplMeshTags" : [ ],
          "otherAbstract" : [ ],
          "publicationDate" : "2020-12-11",
          "chemicals" : [ ],
          "authors" : [
          ]
        },
      }
  1. The script being sent is:
  if (!ctx._source.containsKey('maps')) {
    def m = new HashMap();
    ctx._source['maps'] = m;
  }
  String mapId = params.mapId;
  if (!ctx._source.maps.containsKey(mapId)) {
    ctx._source.maps[mapId] = new ArrayList();
  }
  for (int i = 0; i < params.tags.length; i++) {
    String tag = params.tags[i];
    if(!ctx._source.maps[mapId].contains(tag)){
      ctx._source.maps[mapId].add(tag);
    }
  }
  1. I'm submitting this script with params that look something like this:
params: {
  mapId: 'A',
  tags: ["MyCustomTag"]
}
  1. This script successfully adds the following section to the indexed document's source:
   "maps" : {
        "A" : [
          "MyCustomTag",
        ]
    },

Problem: I cannot query on maps.A successfully for some reason... I want it to be treated like any other text / keyword field in elasticsearch.

can you share your mapping for that index? after that field has been added...

I have to break it into two parts due to its size
Part 1:

{
  "mappings": {
    "_doc": {
      "properties": {
        "abstract": {
          "properties": {
            "category": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            },
            "label": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            },
            "text": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            }
          }
        },
        "abstractCopyright": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "authors": {
          "properties": {
            "affiliations": {
              "properties": {
                "identifier": {
                  "properties": {
                    "id": {
                      "type": "text",
                      "fields": {
                        "keyword": {
                          "type": "keyword",
                          "ignore_above": 256
                        }
                      }
                    },
                    "source": {
                      "type": "text",
                      "fields": {
                        "keyword": {
                          "type": "keyword",
                          "ignore_above": 256
                        }
                      }
                    }
                  }
                },
                "organization": {
                  "type": "text",
                  "fields": {
                    "keyword": {
                      "type": "keyword",
                      "ignore_above": 256
                    }
                  }
                }
              }
            },
            "collective": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            },
            "forename": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            },
            "identifier": {
              "properties": {
                "id": {
                  "type": "text",
                  "fields": {
                    "keyword": {
                      "type": "keyword",
                      "ignore_above": 256
                    }
                  }
                },
                "source": {
                  "type": "text",
                  "fields": {
                    "keyword": {
                      "type": "keyword",
                      "ignore_above": 256
                    }
                  }
                }
              }
            },
            "initials": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            },
            "lastname": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            },
            "suffix": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            },
            "valid": {
              "type": "boolean"
            }
          }
        },
        "chemicals": {
          "properties": {
            "name": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            },
            "registryNumber": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            },
            "ui": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            }
          }
        },
        "genes": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "journal": {
          "properties": {
            "country": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            },
            "issn": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            },
            "nlmId": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            },
            "publicationDate": {
              "type": "date"
            },
            "title": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            },
            "titleAbrv": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            }
          }
        },
        "keywords": {
          "properties": {
            "keyword": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            },
            "majorTopic": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            }
          }
        },
        "language": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "maps": {
          "type": "nested",
          "properties": {
            "A": {
              "type": "text",
              "fields": {
                "raw": {
                  "type": "keyword"
                }
              }
            },
            "B": {
              "type": "text",
              "fields": {
                "raw": {
                  "type": "keyword"
                }
              }
            },
            "C": {
              "type": "text",
              "fields": {
                "raw": {
                  "type": "keyword"
                }
              }
            },
            "D": {
              "type": "text",
              "fields": {
                "raw": {
                  "type": "keyword"
                }
              }
            },
            "E": {
              "type": "text",
              "fields": {
                "raw": {
                  "type": "keyword"
                }
              }
            },
            "F": {
              "type": "text",
              "fields": {
                "raw": {
                  "type": "keyword"
                }
              }
            },
            "G": {
              "type": "text",
              "fields": {
                "raw": {
                  "type": "keyword"
                }
              }
            },
            "H": {
              "type": "text",
              "fields": {
                "raw": {
                  "type": "keyword"
                }
              }
            },
            "I": {
              "type": "text",
              "fields": {
                "raw": {
                  "type": "keyword"
                }
              }
            },
            "J": {
              "type": "text",
              "fields": {
                "raw": {
                  "type": "keyword"
                }
              }
            },
            "K": {
              "type": "text",
              "fields": {
                "raw": {
                  "type": "keyword"
                }
              }
            },
            "L": {
              "type": "text",
              "fields": {
                "raw": {
                  "type": "keyword"
                }
              }
            },
            "M": {
              "type": "text",
              "fields": {
                "raw": {
                  "type": "keyword"
                }
              }
            },
            "N": {
              "type": "text",
              "fields": {
                "raw": {
                  "type": "keyword"
                }
              }
            },
            "V": {
              "type": "text",
              "fields": {
                "raw": {
                  "type": "keyword"
                }
              }
            },
            "Z": {
              "type": "text",
              "fields": {
                "raw": {
                  "type": "keyword"
                }
              }
            }
          }
        },
 

Part 2:

       "meshTags": {
          "properties": {
            "majorTopic": {
              "type": "boolean"
            },
            "name": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            },
            "qualifiers": {
              "properties": {
                "majorTopic": {
                  "type": "boolean"
                },
                "name": {
                  "type": "text",
                  "fields": {
                    "keyword": {
                      "type": "keyword",
                      "ignore_above": 256
                    }
                  }
                },
                "ui": {
                  "type": "text",
                  "fields": {
                    "keyword": {
                      "type": "keyword",
                      "ignore_above": 256
                    }
                  }
                }
              }
            },
            "ui": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            }
          }
        },
        "otherAbstract": {
          "properties": {
            "language": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            },
            "sections": {
              "properties": {
                "category": {
                  "type": "text",
                  "fields": {
                    "keyword": {
                      "type": "keyword",
                      "ignore_above": 256
                    }
                  }
                },
                "label": {
                  "type": "text",
                  "fields": {
                    "keyword": {
                      "type": "keyword",
                      "ignore_above": 256
                    }
                  }
                },
                "text": {
                  "type": "text",
                  "fields": {
                    "keyword": {
                      "type": "keyword",
                      "ignore_above": 256
                    }
                  }
                }
              }
            },
            "type": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            }
          }
        },
        "pmid": {
          "type": "long"
        },
        "publicationDate": {
          "type": "date"
        },
        "supplMeshTags": {
          "properties": {
            "name": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            },
            "type": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            },
            "ui": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            }
          }
        },
        "title": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        }
      }
    }
  }
}

The mapping for the maps field is as I manually set it, as described in my original post. I'm putting that mapping there for maps, indicating which fields (A, B, etc) will be there. All of these fields (A,B, etc) should have the same mapping type though: Text / Keyword.

If I try updating my documents under a new field called mapTags instead of maps, without first updating the mapping in the index I get:

"mapTags": {
          "properties": {
            "A": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            }
          }
        },

A second, less urgent question comes to me after seeing this: does the ignore_above: 256 mean the max size for a keyword is 256 chars, or does it mean that all my keywords combined must be less than 256 chars?

Okay, and interestingly enough, this new field mapTags, for which I did not specify a mapping previously is searchable without issue. So I'm guessing I did something wrong when setting my initial mapping. This should allow me to proceed. Thanks for helping guide me to the solution.

The reason is, that "type": "nested" for the maps field. Requiring you to also use a nested query.

Oooooohh. That makes sense. Thank you!

So this begs the question then - when do I actually need a nested mapping if not for when an object has nested fields?

A common use-case for nested is, when a field is an array, and you need to query more than one field within that array. See Nested field type | Elasticsearch Guide [7.13] | Elastic

Also, you may want to take a look at the flattened data type in order to prevent mapping explosion

hope this helps!

It does! Thank you for all your help. Learning all the elastic things can be really overwhelming, so I really appreciate your support.

1 Like