From 48de01d696d931edf859a5587c3ddc5277474ebf Mon Sep 17 00:00:00 2001 From: Ryan Ernst Date: Mon, 19 May 2025 08:18:09 -0700 Subject: [PATCH] Avoid nested docs in painless execute api (#127991) Painless does not support accessing nested docs (except through _source). Yet the painless execute api indexes any nested docs that are found when parsing the sample document. This commit changes the ram indexing to only index the root document, ignoring any nested docs. fixes #41004 --- docs/changelog/127991.yaml | 6 ++++++ .../painless/action/PainlessExecuteAction.java | 3 ++- .../painless/action/PainlessExecuteApiTests.java | 12 ++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 docs/changelog/127991.yaml diff --git a/docs/changelog/127991.yaml b/docs/changelog/127991.yaml new file mode 100644 index 0000000000000..dead04164ccab --- /dev/null +++ b/docs/changelog/127991.yaml @@ -0,0 +1,6 @@ +pr: 127991 +summary: Avoid nested docs in painless execute api +area: Infra/Scripting +type: bug +issues: + - 41004 diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/action/PainlessExecuteAction.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/action/PainlessExecuteAction.java index 4f34cbd3cc475..d8ed73633b2cc 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/action/PainlessExecuteAction.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/action/PainlessExecuteAction.java @@ -828,7 +828,8 @@ private static Response prepareRamIndex( // This is a problem especially for indices that have no mappings, as no fields will be accessible, neither through doc // nor _source (if there are no mappings there are no metadata fields). ParsedDocument parsedDocument = documentMapper.parse(sourceToParse); - indexWriter.addDocuments(parsedDocument.docs()); + // only index the root doc since nested docs are not supported in painless anyways + indexWriter.addDocuments(List.of(parsedDocument.rootDoc())); try (IndexReader indexReader = DirectoryReader.open(indexWriter)) { final IndexSearcher searcher = new IndexSearcher(indexReader); searcher.setQueryCache(null); diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/action/PainlessExecuteApiTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/action/PainlessExecuteApiTests.java index 56dec6cf4a58d..b6c1696ed55b4 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/action/PainlessExecuteApiTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/action/PainlessExecuteApiTests.java @@ -70,6 +70,18 @@ public void testDefaults() throws IOException { assertThat(e.getCause().getMessage(), equalTo("cannot resolve symbol [doc]")); } + public void testNestedDocs() throws IOException { + ScriptService scriptService = getInstanceFromNode(ScriptService.class); + IndexService indexService = createIndex("index", Settings.EMPTY, "doc", "rank", "type=long", "nested", "type=nested"); + + Request.ContextSetup contextSetup = new Request.ContextSetup("index", new BytesArray(""" + {"rank": 4.0, "nested": [{"text": "foo"}, {"text": "bar"}]}"""), new MatchAllQueryBuilder()); + contextSetup.setXContentType(XContentType.JSON); + Request request = new Request(new Script(ScriptType.INLINE, "painless", "doc['rank'].value", Map.of()), "score", contextSetup); + Response response = innerShardOperation(request, scriptService, indexService); + assertThat(response.getResult(), equalTo(4.0D)); + } + public void testFilterExecutionContext() throws IOException { ScriptService scriptService = getInstanceFromNode(ScriptService.class); IndexService indexService = createIndex("index", Settings.EMPTY, "doc", "field", "type=long");