How to send raw JSON queries with Elasticsearch Java Client 8

Hello,

I’m currently migrating from Elasticsearch 7 to 8 in a Java application, and I’m running into issues when trying to perform searches using raw JSON queries.

In Elasticsearch 7, I used the Low Level REST Client like this:

final String endpoint = String.format("/%s/%s", this.alias, "_search");
final Map<String, String> params = new HashMap<>();
// add params if needed

final Request request = new Request(HttpMethod.POST, endpoint);
request.addParameters(params);
request.setJsonEntity(searchJson); // searchJson is a String
final Response response = this.clientSupplier.get().getLowLevelClient().performRequest(request);

Now with the Java client for Elasticsearch 8, I can't seem to do the same. The JSON I'm using includes features like script inside aggregations, which can't be mapped directly to the new SearchRequest class, but the same JSON works when sent through Postman. Here's a simplified example of the kind of query I'm trying to send:

{
  "size": 0,
  "query": {
    "bool": {
      "must": [
        { "bool": { "must": [] } },
        {
          "terms": {
            "_acl": ["any", "000000000000000000000009", "000000000000000000000039", "eba000000005000000000003", "eba000000000000000000200", "eba000000000000000000205"],
            "boost": 1.0
          }
        }
      ]
    }
  },
  "aggs": {
    "rootGroup": {
      "date_histogram": {
        "format": "dd/MM/yyyy",
        "time_zone": "America/Sao_Paulo",
        "min_doc_count": 1,
        "script": "Object calculate(def doc) { ... }",
        "calendar_interval": "day"
      },
      "aggs": {}
    },
    "nulo": {
      "missing": {
        "script": "Object calculate(def doc) { ... }"
      }
    }
  }
}

I tried using client.search(b -> b.index(index).withJson(new StringReader(searchJson)), Map.class);, but it fails with JsonpMappingException because the structure doesn't map cleanly to the Java classes.

Is there a recommended way in Elasticsearch 8 Java client to send a raw JSON query string, similar to how it was done with the Low Level REST Client in version 7?

Thanks in advance!

Hey

I'm wondering if you are looking for this: Creating API objects from JSON data | Elastic Documentation

HTH

Hey.

Yes, it's something along those lines. However, as I mentioned earlier, the JSON I receive can include elements that don’t map to the SearchRequest class in Elasticsearch 8 — for example, a missing aggregation that contains a script, like in the example above. I tried using the approach you suggested, but I ran into JSON deserialization errors.

I ended up handling it like this:

final JsonStructure jsonStructure = Json.createReader(new StringReader(searchJson)).read();

final SimpleEndpoint<Object, Object> searchEndpoint = new SimpleEndpoint<>("es-search",
    method -> "POST",
    requestUrl -> endpoint,
    pathParameters -> this.ignoreUnavailableIndex ? Map.of("ignore_unavailable", "true") : Map.of(),
    queryParameters -> Map.of(),
    headers -> Map.of(),
    body -> jsonBody,
    JsonpDeserializer.of(Object.class));

final BinaryResponse r = client._transport().performRequest(
    PostRequest.of(b -> b),
    simpleEndpoint.withBinaryResponse(),
    this.clientSupplier.get()._transportOptions()
        .toBuilder()
        .setParameter("typed_keys", "false")
        .build()
);

This works for now, but it doesn’t feel like the "correct" or intended way to handle this in the Elasticsearch 8 Java client.