11

I’m currently using Elasticsearch V2.3.1. I want to use the following Elasticsearch query in Java.

POST /twitter/_update_by_query
{
  "script": {
    "inline": "ctx._source.List = [‘Item 1’,’Item 2’]”
  },
  "query": {
    "term": {
      "user": "kimchy"
    }
  }
}

The above query searches for “user” named “kimchy” and updates the “List” field with given values. This query updates multiple documents at the same time. I read about the Update API for Java here https://www.elastic.co/guide/en/elasticsearch/client/java-api/2.3/java-docs-update.html but couldn’t find what I was looking for. The Update API for Java only talks about updating single document at a time. Is there any way to update multiple documents? Sorry if I’m missing something obvious. Thank you for your time.

Update:

I tried the below Java Code:

Client client = TransportClient.builder().addPlugin(ReindexPlugin.class)
    .build().addTransportAddress(new InetSocketTransportAddress(
        InetAddress.getByName("127.0.0.1"), 9300));

UpdateByQueryRequestBuilder ubqrb = UpdateByQueryAction.INSTANCE
    .newRequestBuilder(client);

Script script = new Script("ctx._source.List = [\"Item 1\",\"Item 2\"]");

//termQuery is not recognised by the program
BulkIndexByScrollResponse r = ubqrb.source("twitter").script(script)
    .filter(termQuery("user", "kimchy")).execute().get();

So I edited the Java Program as above and the termQuery is not identified by Java. May I know what I'm doing wrong here? Thanks.

A Coder Gamer
  • 840
  • 1
  • 10
  • 31

2 Answers2

16

As of ES 2.3, the update by query feature is available as the REST endpoint _update_by_query but nor for Java clients. In order to call this endpoint from your Java client code, you need to include the reindex module in your pom.xml, like this

<dependency>
    <groupId>org.elasticsearch.module</groupId>
    <artifactId>reindex</artifactId>
    <version>2.3.2</version>
</dependency>

Then you need to include this module when building your client:

clientBuilder.addPlugin(ReindexPlugin.class);

Finally you can call it like this:

UpdateByQueryRequestBuilder ubqrb = UpdateByQueryAction.INSTANCE.newRequestBuilder(client);

Script script = new Script("ctx._source.List = [\"Item 1\",\"Item 2\"]");

BulkIndexByScrollResponse r = ubqrb.source("twitter")
    .script(script)
    .filter(termQuery("user", "kimchy"))
    .get();

UPDATE

If you need to specify the type(s) the update should focus on, you can do so:

ubqrb.source("twitter").source().setTypes("type1");
BulkIndexByScrollResponse r = ubqrb.script(script)
    .filter(termQuery("user", "kimchy"))
    .get();
Val
  • 207,596
  • 13
  • 358
  • 360
  • 2
    You need to add `import static org.elasticsearch.index.query.QueryBuilders.termQuery;` – Val May 13 '16 at 03:53
  • Hi @Val, it worked but this way(using filter in BulkIndexByScrollResponse) I can only update one document that has a user named "Kimchy". Is it possible to update multiple documents using setQuery in BulkIndexByScrollResponse? or possibly any other way? – A Coder Gamer May 13 '16 at 16:32
  • Of course, you can craft any kind of query. That was just an example. What's your query? – Val May 13 '16 at 16:32
  • Hi @Val, Is their a way to set the doc type in this type of query. – Tushar garg Jun 27 '16 at 09:38
  • @Val, is it possible to use params in this script? – Taras Kohut Oct 28 '16 at 16:40
  • @TarasKohut yes, just use the forth param in the `Script` constructor – dazewell Nov 03 '16 at 10:11
  • Maybe I missed something, but I've got NPE trying to execute `.get()`. It gets failed at the `TransportProxyClient::execute(...)` because there's no proxy found for this kind of `Action`. Any help'd be appretiated. – dazewell Nov 03 '16 at 10:13
  • @TarasKohut yes you can use the [`Script` constructor with four parameters](https://github.com/elastic/elasticsearch/blob/185dff73461ae384f44fda5c7883fa6ba5e8c466/core/src/main/java/org/elasticsearch/script/Script.java#L64-L66) – Val Nov 03 '16 at 10:14
  • @Val don't you have any ideas on my problem above? I've registered the plugin as you've said and executing exactly the same scenario but with no luck. Do I need something else to get it working? – dazewell Nov 03 '16 at 10:19
  • @dazewell I'd say it'd be better to create another question with your specific problem, you'll have better chances of getting answers. – Val Nov 03 '16 at 10:21
  • @Val thanks. I've created another [question](http://stackoverflow.com/q/40399689/4806529). If you'll have time, could you please check it out? – dazewell Nov 03 '16 at 10:55
  • @Val, would it be possible to describe what is the type of `clientBuilder` and/or how can you get it? Thanks a lot. – Adam Libuša Jul 12 '17 at 15:26
  • 1
    Just a hint for those who'd use ES version `5.5.0` or similar: The plugin has to be added as a second parameter in `PreBuiltTransportClient`'s constructor. – Adam Libuša Jul 13 '17 at 11:49
3

In ES 7.9 this also works using UpdateByQueryRequest

Map<String, Object> map = new HashMap<String, Object>();

UpdateByQueryRequest updateByQueryRequest = new UpdateByQueryRequest("indexName");
updateByQueryRequest.setConflicts("proceed");
updateByQueryRequest.setQuery(new TermQueryBuilder("_id", documentId));
Script script = new Script(ScriptType.INLINE, "painless",
        "ctx._source = params", map);
updateByQueryRequest.setScript(script);
Usman
  • 949
  • 9
  • 12