﻿---
title: Elasticsearch Java Client 9.3.0
description: Discover what changed in the 9.3.0 version of the Java client. This version presents many updates to existing fields that were wrongly mapped, or incomplete...
url: https://www.elastic.co/elastic/docs-builder/docs/2689/release-notes/elasticsearch/clients/java/9-3-0
products:
  - Elasticsearch Client
  - Elasticsearch Java Client
---

# Elasticsearch Java Client 9.3.0
Discover what changed in the 9.3.0 version of the Java client.

## Breaking changes

This version presents many updates to existing fields that were wrongly mapped, or incomplete. Here is the complete list of changes:
<dropdown title="String to List<String>">
  - elasticsearch.indices.update_aliases.AddAction
    - `indexRouting`: modified from `String` to `List<String>`, now required
  - `routing`: modified from `String` to `List<String>`, now required
  - `searchRouting`: modified from `String` to `List<String>`, now required
  - elasticsearch.indices.AddBlockRequest
    - `index`: modified from `String` to `List<String>`
  - elasticsearch.indices.Alias
    - `indexRouting`: modified from `String` to `List<String>`, now required
  - `routing`: modified from `String` to `List<String>`, now required
  - `searchRouting`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.bulk.BulkOperationBase
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.BulkRequest
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.security.ClearCachedPrivilegesRequest
    - `application`: modified from `String` to `List<String>`
  - elasticsearch.core.search.CompletionSuggestOption
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.CountRequest
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.CreateRequest
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.indices.DataStreamsStatsRequest
    - `name`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.DeleteByQueryRequest
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.DeleteRequest
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.snapshot.DeleteSnapshotRequest
    - `snapshot`: modified from `String` to `List<String>`
  - elasticsearch.core.reindex.Destination
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.ExistsRequest
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.ExistsSourceRequest
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.ExplainRequest
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.graph.ExploreRequest
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.FieldCapsRequest
    - `filters`: modified from `String` to `List<String>`, now required
  - elasticsearch._types.query_dsl.FieldLookup
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.text_structure.FindFieldStructureRequest
    - `columnNames`: modified from `String` to `List<String>`, now required
  - elasticsearch.text_structure.FindMessageStructureRequest
    - `columnNames`: modified from `String` to `List<String>`, now required
  - elasticsearch.fleet.FleetSearchRequest
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.GetRequest
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.GetSourceRequest
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch._types.InlineGet
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.IndexRequest
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch._types.query_dsl.LikeDocument
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.MgetRequest
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch._types.query_dsl.MoreLikeThisQuery
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.msearch.MultisearchHeader
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.MsearchRequest
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.MtermvectorsRequest
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.mget.MultiGetOperation
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.mtermvectors.MultiTermVectorsOperation
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.OpenPointInTimeRequest
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch._types.query_dsl.PercolateQuery
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.indices.PutAliasRequest
    - `indexRouting`: modified from `String` to `List<String>`, now required
  - `routing`: modified from `String` to `List<String>`, now required
  - `searchRouting`: modified from `String` to `List<String>`, now required
  - elasticsearch.indices.RemoveBlockRequest
    - `index`: modified from `String` to `List<String>`
  - elasticsearch.core.SearchRequest
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.SearchShardsRequest
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.SearchTemplateRequest
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.async_search.SubmitRequest
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch._types.query_dsl.TermsLookup
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.TermsEnumRequest
    - `index`: modified from `String` to `List<String>`
  - elasticsearch.core.TermvectorsRequest
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.UpdateByQueryRequest
    - `routing`: modified from `String` to `List<String>`, now required
  - elasticsearch.core.UpdateRequest
    - `routing`: modified from `String` to `List<String>`, now required
</dropdown>

<dropdown title="Number to Integer">
  - elasticsearch._types.GeoHashPrecision
    - `geohashLength`: modified from `Number` to `Integer`
  - elasticsearch._types.aggregations.GeoTileGridAggregation
    - `precision`: modified from `Number` to `Integer`
</dropdown>

<dropdown title="List<String> to List<NodesInfoMetric>">
  - elasticsearch.nodes.NodesInfoRequest
    - `metric`: modified from `List<String>` to `List<NodesInfoMetric>`
  - elasticsearch.nodes.NodesStatsRequest
    - `metric`: modified from `List<String>` to `List<NodesInfoMetric>`
  - elasticsearch.nodes.NodesUsageRequest
    - `metric`: modified from `List<String>` to `List<NodesInfoMetric>`
</dropdown>

<dropdown title="Field removals">
  - elasticsearch.inference.PutAnthropicRequest
    - `chunkingSettings`: removed
  - elasticsearch.inference.PutContextualaiRequest
    - `chunkingSettings`: removed
  - elasticsearch.inference.PutDeepseekRequest
    - `chunkingSettings`: removed
  - elasticsearch.core.BulkRequest
    - `type`: removed
</dropdown>

<dropdown title="Type removals">
  - elasticsearch.indices.DataStreamLifecycleDownsampling: **removed**
  - elasticsearch.cat.HelpResponse: **removed**
  - elasticsearch.nodes.HotThreadsResponse: **removed**
  - elasticsearch.core.reindex_rethrottle.ReindexStatus: **removed**
  - elasticsearch.ml.evaluate_data_frame.ResponseBody: **removed**
  - elasticsearch.ml.evaluate_data_frame.ResponseBodyVariant: **removed**
</dropdown>

<dropdown title="Other changes">
  - elasticsearch.cluster.ComponentTemplateSummary
    - `dataStreamOptions`: modified from `elasticsearch.indices.DataStreamOptionsTemplate` to `elasticsearch.indices.DataStreamOptions`
  - elasticsearch.indices.DataStreamLifecycle
    - `downsampling`: modified from `elasticsearch.indices.DataStreamLifecycleDownsampling` to `List<elasticsearch.indices.DownsamplingRound>`
  - elasticsearch.ml.GetCategoriesRequest
    - `categoryId`: modified from `String` to `Long`
  - elasticsearch.indices.IndicesStatsRequest
    - `metric`: modified from `List<String>` to `List<elasticsearch._types.CommonStatsFlag>`
  - elasticsearch.indices.IndexTemplateSummary
    - `dataStreamOptions`: modified from `elasticsearch.indices.DataStreamOptionsTemplate` to `elasticsearch.indices.DataStreamOptions`
  - elasticsearch.cluster.allocation_explain.NodeAllocationExplanation
    - `weightRanking`: modified from `int` to `Integer`
  - elasticsearch.nodes.NodesStatsRequest
    - `indexMetric`: modified from `List<String>` to `List<elasticsearch._types.CommonStatsFlag>`
  - elasticsearch.cluster.PutComponentTemplateRequest
    - `template`: modified from `elasticsearch.indices.IndexState` to `elasticsearch.indices.put_index_template.IndexTemplateMapping`
  - elasticsearch.indices.PutDataLifecycleRequest
    - `downsampling`: modified from `elasticsearch.indices.DataStreamLifecycleDownsampling` to `List<elasticsearch.indices.DownsamplingRound>`
  - elasticsearch.ingest.PutPipelineRequest
    - `ifVersion`: modified from `Long` to `Integer`
  - elasticsearch.core.RankEvalRequest
    - `searchType`: modified from `String` to `elasticsearch._types.SearchType`
  - elasticsearch.core.reindex_rethrottle.ReindexTask
    - `status`: modified from `elasticsearch.core.reindex_rethrottle.ReindexStatus` to `elasticsearch._types.ReindexStatus`
  - elasticsearch._types.RRFRetriever
    - `retrievers`: modified from `List<elasticsearch._types.Retriever>` to `List<elasticsearch._types.RRFRetrieverEntry>`
  - elasticsearch.core.reindex.Source
    - `sourceFields`: modified from `List` to `elasticsearch.core.search.SourceConfig`, now optional
  - elasticsearch.cluster.StateRequest
    - `metric`: modified from `List<String>` to `List<elasticsearch.cluster.state.ClusterStateMetric>`
</dropdown>


## Features and enhancements

<dropdown title="Faster vector ingestion with Base64 format">
  Elasticsearch 9.3 introduces the possibility to ingest vectors in a Base64 string format instead of float arrays, with a substantial performance gain.
  To make this feature easier to use, the Java Client 9.3 provides an utility class, `AbstractBase64VectorDocument`, that can be extended to facilitate conversion from float[] to Base64 string in the format accepted by the server.Example usage:
  ```java
  public final class CustomVectorDoc extends AbstractBase64VectorDocument {
      private String docid;
      private String title;
      private String text;
    ...
  }

  ...

  try (ElasticsearchClient client = ElasticsearchClient.of(e -> e
          .host("your-host")
          .apiKey("your-api-keys"))) {

      float[] embeddings = embeddingModel.getEmbeddings("content");

      // Converting vector from array of floats to base64 using utility class
      CustomVectorDoc customVectorDoc = new CustomVectorDoc("docID", "title", "content", embeddings);

      // Indexing the custom vector class normally
      client.index(i ->i
        .index(INDEX)
        .document(customVectorDoc)
      );
  }  
  ```
  Note that while normally Elasticsearch automatically detects vector fields and creates a new index with the correct mapping and vector dimension, when ingesting vectors in Base64 format the index must be created first and all vector properties must be specified in the mapping.
  A complete example is available in the Java Client repository as a [unit test](https://github.com/elastic/elasticsearch-java/blob/9.3/java-client/src/test/java/co/elastic/clients/elasticsearch/_helpers/vector/Base64VectorTest.java).
</dropdown>

<dropdown title="Rebuild pattern to convert requests back to their builder">
  Once an instance of a class has been created, all its fields are immutable, so it's not possible to apply modifications without having to create a new instance.
  A new method `rebuild()` has been added to all requests and subclasses that converts an object back to its builder, keeping the value of all fields as they were set.Example usage:
  ```java
   SearchRequest searchRequest = SearchRequest.of(s -> s
          .size(20)
          .index("test")
          .query(q -> q.match(m -> m.field("field").query("value")))
  );
  SearchRequest.Builder builder = searchRequest.rebuild();

  SearchRequest searchRequestRebuilt = builder
          // can update values here
          .build();
  ```
</dropdown>

<dropdown title="Support for text-based endpoints">
  Correctly handling endpoints that return plain text responses, such as [hot_threads](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-nodes-hot-threads) and [_cat](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-cat-help).Example usage:
  ```java
  TextResponse resp = elasticsearchClient.cat().help();
  System.out.println(resp.value());
  ```
</dropdown>

<dropdown title="Msearch and Search requests compatibility">
  Msearch and Search requests (and the template in ScriptSource) have similar bodies, but they are different classes (`SearchRequest` vs `SearchRequestBody`) due to how the client is generated from the common [API specification](https://github.com/elastic/elasticsearch-specification).
  This version introduces overload methods in the builders of Msearch's `RequestItem` and `ScriptSource` so that they can also accept a `SearchRequest` instance instead of only the original `SearchRequestBody`.Example usage:
  ```java
  // Normal search request
  SearchRequest searchRequest = SearchRequest.of(b -> b
                  .size(10)
                  .from(10)
                  .query(q -> q
                          .matchAll(m -> m)
                  )
          );

  // Using it to build Msearch
  MsearchRequest msearchRequestOverload = MsearchRequest.of(ms -> ms
          .searches(s -> s
                  .header(h -> h.index("index"))
                  .body(searchRequest)
          )
  );

  // Or script source
  ScriptSource scriptSourceOverload = ScriptSource.of(s -> s
          .scriptTemplate(searchRequest)
  );
  ```
</dropdown>

<dropdown title="Typed builder for Time">
  Added an overload setter to `Time` so that it can be built using an integer and a `TimeUnit`, instead of just a plain string.Example usage:
  ```java
  // Old builder
  OpenPointInTimeRequest opr = OpenPointInTimeRequest.of(o -> o
                  .index("test")
                  .keepAlive(k -> k
                          .time("5s")
                  )
          );

  // New builder
  OpenPointInTimeRequest opr = OpenPointInTimeRequest.of(o -> o
          .index("test")
          .keepAlive(k -> k
                  .time(5, TimeUnit.Seconds)
          )
  );
  ```
</dropdown>

<dropdown title="Lighter elasticsearch-rest5-client artifact">
  [elasticsearch-rest5-client](https://mvnrepository.com/artifact/co.elastic.clients/elasticsearch-rest5-client) used to have a dependency on [jackson-core](https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core) which was only used in the utility class `ElasticsearchNodesSniffer`.
  The dependency has been replaced with the more lightweight [jsonp parsson](https://mvnrepository.com/artifact/org.eclipse.parsson/jakarta.json).
</dropdown>


## Deprecations

Nothing was deprecated in this version of the client.