From 142e15c095dfa4e89a17200a3776576bf9753a0a Mon Sep 17 00:00:00 2001 From: Chakru <161002324+chakru-r@users.noreply.github.com> Date: Thu, 13 Nov 2025 00:06:06 +0530 Subject: [PATCH] fix(es): npe when applying scripted update on es --- .../client/shim/impl/Es8SearchClientShim.java | 27 +++++++++++-------- .../search/update/ESWriteDAOTest.java | 2 ++ 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/metadata-io/src/main/java/com/linkedin/metadata/search/elasticsearch/client/shim/impl/Es8SearchClientShim.java b/metadata-io/src/main/java/com/linkedin/metadata/search/elasticsearch/client/shim/impl/Es8SearchClientShim.java index 39c07f7fe68e20..0b8a6193db5ca6 100644 --- a/metadata-io/src/main/java/com/linkedin/metadata/search/elasticsearch/client/shim/impl/Es8SearchClientShim.java +++ b/metadata-io/src/main/java/com/linkedin/metadata/search/elasticsearch/client/shim/impl/Es8SearchClientShim.java @@ -1641,6 +1641,21 @@ protected void addToProcessor(BulkIngester processor, DocWriteRequest writ if (writeRequest instanceof UpdateRequest) { UpdateRequest update = (UpdateRequest) writeRequest; Script script = convertScript(update.script()); + + @SuppressWarnings("rawtypes") + UpdateAction.Builder actionBuilder = + new UpdateAction.Builder() + .detectNoop(update.detectNoop()) + .docAsUpsert(update.docAsUpsert()) + .script(script) + .upsert(update.upsert()); + + // Only set doc if it exists (not present for script-only updates) + if (update.doc() != null) { + actionBuilder.doc( + XContentHelper.convertToMap(update.doc().source(), true, XContentType.JSON).v2()); + } + operation = new BulkOperation( new UpdateOperation.Builder<>() @@ -1651,17 +1666,7 @@ protected void addToProcessor(BulkIngester processor, DocWriteRequest writ .requireAlias(writeRequest.isRequireAlias()) .index(writeRequest.index()) .routing(writeRequest.routing()) - .action( - new UpdateAction.Builder<>() - .doc( - XContentHelper.convertToMap( - update.doc().source(), true, XContentType.JSON) - .v2()) - .detectNoop(update.detectNoop()) - .docAsUpsert(update.docAsUpsert()) - .script(script) - .upsert(update.upsert()) - .build()) + .action(actionBuilder.build()) .build()); } else if (writeRequest instanceof DeleteRequest) { DeleteRequest deleteRequest = (DeleteRequest) writeRequest; diff --git a/metadata-io/src/test/java/com/linkedin/metadata/search/update/ESWriteDAOTest.java b/metadata-io/src/test/java/com/linkedin/metadata/search/update/ESWriteDAOTest.java index 00d8b67d91060d..6fef75ec56de5c 100644 --- a/metadata-io/src/test/java/com/linkedin/metadata/search/update/ESWriteDAOTest.java +++ b/metadata-io/src/test/java/com/linkedin/metadata/search/update/ESWriteDAOTest.java @@ -116,6 +116,7 @@ public void testDeleteDocument() { assertEquals(capturedRequest.id(), TEST_DOC_ID); } + @Test public void testApplyScriptUpdate() { String scriptSource = "ctx._source.field = params.newValue"; Map scriptParams = new HashMap<>(); @@ -135,6 +136,7 @@ public void testApplyScriptUpdate() { assertFalse(capturedRequest.detectNoop()); assertTrue(capturedRequest.scriptedUpsert()); assertEquals(NUM_RETRIES, capturedRequest.retryOnConflict()); + assertNull(capturedRequest.doc()); // For scripted updates, this is null // Verify script content and parameters Script script = capturedRequest.script();