6

According to the official documentation Update API - Upserts one can use scripted_upsert in order to handle update (for existing document) or insert (for new document) form within the script. The thing is they never show how the script should look to do that. The Java - Update API Doesn't have any information on the ScriptUpsert uses.

This is the code I'm using:

//My function to build and use the upsert
public void scriptedUpsert(String key, String parent, String scriptSource, Map<String, ? extends Object> parameters) {
    Script script = new Script(scriptSource, ScriptType.INLINE, null, parameters);
    UpdateRequest request = new UpdateRequest(index, type, key);
    request.scriptedUpsert(true);
    request.script(script);
    if (parent != null) {
        request.parent(parent);
    }
    this.bulkProcessor.add(request);
}

//A test call to validate the function
String scriptSource = "if (!ctx._source.hasProperty(\"numbers\")) {ctx._source.numbers=[]}";
Map<String, List<Integer>> parameters = new HashMap<>();
List<Integer> numbers = new LinkedList<>();
numbers.add(100);
parameters.put("numbers", numbers);

bulk.scriptedUpsert("testUser", null, scriptSource, parameters);

And I'm getting the following exception when "testUser" documents doesn't exists:
DocumentMissingException[[user][testUser]: document missing

How can I make the scriptUpsert work from the Java code?

Sumit
  • 2,190
  • 23
  • 31
Roee Gavirel
  • 18,955
  • 12
  • 67
  • 94

2 Answers2

6

This is how a scripted_upsert command should look like (and its script):

POST /sessions/session/1/_update
{
  "scripted_upsert": true,
  "script": {
    "inline": "if (ctx.op == \"create\") ctx._source.numbers = newNumbers; else ctx._source.numbers += updatedNumbers",
    "params": {
      "newNumbers": [1,2,3],
      "updatedNumbers": [55]
    }
  },
  "upsert": {}
}

If you call the above command and the index doesn't exist, it will create it, together with the newNumbers values in the new documents. If you call again the exact same command the numbers values will become 1,2,3,55.

And in your case you are missing "upsert": {} part.

user1870400
  • 6,028
  • 13
  • 54
  • 115
Andrei Stefan
  • 51,654
  • 6
  • 98
  • 89
  • 1
    At the time I posted this @user1870400, `inline` didn't exist. This changed with time and with new versions changes. Your update is correct, but saying that the "answer is incorrect" is a bit stretched ;-). – Andrei Stefan Jul 02 '18 at 07:10
  • If you paste the same exact payload into ES > 5 or 6 it fails even now. – user1870400 Jul 02 '18 at 07:23
  • 2 years ago there was no 5 or 6 version. – Andrei Stefan Jul 02 '18 at 10:42
  • okies what I meant to say was even the above answer(after the update) still fails for version 5 and 6. And I understand the version of 5 and 6 still exists but it's better to modify the above answer to something that works. my 2 cents – user1870400 Jul 02 '18 at 10:48
1

As Andrei suggested I was missing the upsert part, changing the function to:

public void scriptedUpsert(String key, String parent, String scriptSource, Map<String, ? extends Object> parameters) {
    Script script = new Script(scriptSource, ScriptType.INLINE, null, parameters);
    UpdateRequest request = new UpdateRequest(index, type, key);
    request.scriptedUpsert(true);
    request.script(script);
    request.upsert("{}"); // <--- The change
    if (parent != null) {
        request.parent(parent);
    }
    this.bulkProcessor.add(request);
}

Fix it.

Roee Gavirel
  • 18,955
  • 12
  • 67
  • 94