Java Api for UpdateByQuery requests

I've written a groovy script and tested the update_by_query rest functionality using Sense. Everything works perfectly. Then I wanted to simply take the JSON I use in Sense and port that over just like I do with the other query requests using "setSource". That clearly isn't the same thing for UpdateByQuery requests.

I tried to do what was suggested at Java API corresponding to update_by_query but get a NullPointerException when the transport attempts to find a proxy relating to the update by query action type. Is there some magic I'm supposed to know about to get my ES client transport proxy to know about that action?

I thought maybe it was because the actual plugin wasn't installed in the ES node. Fixed that. Still get NPE.

Basically, I don't see any documentation on how to actually do the equivalent update_by_query REST call using the Java transport and the associated query builder APIs. Any tips? Below is the code I've come up with so far...

            //this represents the query part of the update_by_query request. Just looks for a single but unique field
	String json = Queries.buildQueryJson(getClass(), UPDATE_TAGS, params);
	
            //my "context" object abstracts away access to the underlying ES transport client so I can mock it up if
           //a mock library ever became available
	SearchRequestBuilder search = SearchAction.INSTANCE.newRequestBuilder(context.getESClient());

            //I read in the referenced post that I should explicitly set the types and index, so I do that here. And
           //figured I could go ahead and do what I do in other search queries that work, and just set the JSON source
	search.setIndices(index).setTypes(type).setSource(json);
	
            //don't know if this is the right thing to do. But using UpdateByQueryRequestBuilder didn't make a diff
           //on whether I get NPE when I execute query
	UpdateByQueryRequest request = new UpdateByQueryRequest(search.request());
	
            //parameters for my groovy script
	Map<String, Object> scriptParams = new HashMap<>();
	DomainTracking domainTracking = new DomainTracking();
	domainTracking.setDomainId(domainId);
	
	LabelAndCount tag = new LabelAndCount();
	tag.setLabel(label);
	tag.setCount(count);
	
	scriptParams.put("template", domainTracking);
	scriptParams.put("tag", tag);

            //script is a file with params above installed in my config/scripts dir for ES node
	request.setScript(new Script("TagItem", ScriptType.FILE, "groovy", scriptParams));
	
            //get NPE when transport attempts to reference a proxy looked up by the UpdateByQueryAction type.
	context.getESClient().execute(UpdateByQueryAction.INSTANCE, request).actionGet();

It is kind of hard to tell what happened without a stacktrace. Not finding a transport proxy sounds like it could be caused by missing this part of building the transport client:

clientBuilder.addPlugin(ReindexPlugin.class);

It is kind of hard to tell though.

OK, that was a bit of magic sauce I wasn't aware of. It got me a little further. Now getting write exception when attempting to write my custom objects. How do I pass the structures I want to update down to the script? Even if it's serializable, the script won't have access to the class itself. In the Sense playground, I can just create the JSON and magic happens. I tried turning it into JSON first, but then groovy script complains about strings not having the fields I'm looking for. What's the right way to pass in the correct object types?

Caused by: java.io.IOException: Can't write type [class com.triplet.store.impl.elasticsearch.dao.DomainTracking]
at org.elasticsearch.common.io.stream.StreamOutput.writeGenericValue(StreamOutput.java:420)
at org.elasticsearch.common.io.stream.StreamOutput.writeGenericValue(StreamOutput.java:380)
at org.elasticsearch.common.io.stream.StreamOutput.writeMap(StreamOutput.java:324)
at org.elasticsearch.script.Script.writeTo(Script.java:169)
at org.elasticsearch.common.io.stream.StreamOutput.writeOptionalStreamable(StreamOutput.java:472)
at org.elasticsearch.index.reindex.AbstractBulkIndexByScrollRequest.writeTo(AbstractBulkIndexByScrollRequest.java:70)
at org.elasticsearch.transport.netty.NettyTransport.sendRequest(NettyTransport.java:874)
at org.elasticsearch.transport.TransportService.sendRequest(TransportService.java:329)
at org.elasticsearch.action.TransportActionNodeProxy.execute(TransportActionNodeProxy.java:51)
at org.elasticsearch.client.transport.support.TransportProxyClient$1.doWithNode(TransportProxyClient.java:58)
at org.elasticsearch.client.transport.TransportClientNodesService.execute(TransportClientNodesService.java:212)
at org.elasticsearch.client.transport.support.TransportProxyClient.execute(TransportProxyClient.java:55)
at org.elasticsearch.client.transport.TransportClient.doExecute(TransportClient.java:288)
at org.elasticsearch.client.support.AbstractClient.execute(AbstractClient.java:359)
at org.elasticsearch.client.support.AbstractClient.execute(AbstractClient.java:348)

Ok, got it. Record the object fields in a map, not in their native Java types. That worked. Thanks for the tip on adding plugin to client builder. That did the trick.

All that is supported in there are Map and List and things like String and Integer and Long and Byte and Date and ReadableInstant.