Roee Gavirel
Roee Gavirel

Reputation: 19463

Using ElasticSearch's script_upsert to create a document

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?

Upvotes: 6

Views: 6002

Answers (2)

Andrei Stefan
Andrei Stefan

Reputation: 52366

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.

Upvotes: 7

Roee Gavirel
Roee Gavirel

Reputation: 19463

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.

Upvotes: 2

Related Questions