Issue 1:
I'm running version 0.19.9

curl -XGET 'http://xxx:9200/_cluster/health?pretty=true'

{

"cluster_name" : "elasticsearch",

"status" : "yellow",

"timed_out" : false,

"number_of_nodes" : 2,

"number_of_data_nodes" : 1,

"active_primary_shards" : 85,

"active_shards" : 85,

"relocating_shards" : 0,

"initializing_shards" : 0,

"unassigned_shards" : 85

}

This works:

curl -XPUT xxx:9200/test/test/1 -d '{"counter" : 1, "tags" : ["fubar1"]}'

curl -XPOST 'xxx:9200/test/test/1/_update' -d '{"script" : "ctx._source.tags += tag","params": {"tag":"fubar2"}}'

This does not work:

curl -XPUT xxx:9200/test/test/2 -d '{"counter" : 1, "@tags" : ["fubar1"]}'

curl -XPOST 'xxx:9200/test/test/2/_update' -d '{"script" : "ctx._source.@tags += tag","params": {"tag":"fubar2"}}'

{"error":"ElasticSearchIllegalArgumentException[failed to execute script]; nested: ArrayIndexOutOfBoundsException[0]; ","status":400}

Posted in mailing list:

https://groups.google.com/d/topic/elasticsearch/SZgbpMj00lk/discussion

Issue 2:
Background / High Level Goal

While working on #14620 I noticed that the current listener-based client API does not compose, i.e. I cannot build processing pipelines based on a response future.

For example, in the Java client implementation classes, I want to write code like:

// 'X' is some not yet specified interface potentially extending ActionFuture
// for backwards compatibility
public X<BulkRequest> bulk(BulkRequest request) {
return Retry.withBackoff(() -> client.bulk(request))
// not important here what #doCleanup does exactly
.onCompletion((response) -> doCleanup())
.onException((ex) -> doCleanup());
}

And I want to do all that without knowing what any potential caller of the Java client API is doing. The caller should just be able to add its operations on top, i.e. we want to build a pipeline of operations, e.g.:

client()
.bulk(request)
.onCompletion((response) -> updateUI())
.onException((ex) -> showErrorMessage(ex));

Current Status

Chaining of listeners is currently also doable but listeners need to delegate explicitly and the code gets very tightly coupled and ugly.

Possible Solution Approach

Starting with Java 8, the JDK provides CompletableFuture which allows to create processing pipelines. However, the CompletableFuture API is very hard to understand and I doubt we need its whole complexity for our use case.

Nevertheless, it could be worthwhile to base the internal implementation on CompletableFuture and just expose parts the API.

Necessary Steps

Start investigating whether CompletableFuture is a good fit for our requirements and flesh out an updated client API (ideally without breaking backwards compatibility, even on master)

Deprecate ActionListener and all methods in the Java client API that take one as parameter (to be removed with next major version)

Add new methods to ActionFuture to allow for chaining. This way, the current API methods that return an ActionFuture will stay but we can get rid of all ActionListener methods. Deprecated methods based on ActionListener can be simply reimplemented internally on top of the new API.

Revisit implementations of ActionFuture (whether we still need them at all) and provide a new default implementation that delegates to CompletableFuture

Update the client documentation with hints on how to migrate the API

(As separate PRs) Adapt internal implementation to take advantage of pipelining.