| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 | [[java-rest-high-level-migration]]== Migration GuideThis section describes how to migrate existing code from the `TransportClient`to the new Java High Level REST Client released with the version 5.6.0of Elasticsearch.=== Motivations around a new Java clientThe existing `TransportClient` has been part of Elasticsearch since https://github.com/elastic/elasticsearch/blob/b3337c312765e51cec7bde5883bbc0a08f56fb65/modules/elasticsearch/src/main/java/org/elasticsearch/client/transport/TransportClient.java[its very first commit]. It is a special client as it uses the transport protocol to communicate with Elasticsearch, which causes compatibility problems if the client is not on the same version as the Elasticsearch instances it talks to.We released a low-level REST client in 2016, which is based on the well known Apache HTTPclient and it allows to communicate with an Elasticsearch cluster in any version using HTTP.On top of that we released the high-level REST client which is based on the low-level clientbut takes care of request marshalling and response un-marshalling.If you're interested in knowing more about these changes, we wrote a blog post about thehttps://www.elastic.co/blog/state-of-the-official-elasticsearch-java-clients[state of the official Elasticsearch Java clients].=== PrerequisiteThe Java High Level Rest Client requires Java `1.8` and can be used to send requeststo an <<java-rest-high-compatibility,Elasticsearch cluster in a compatible version>>.=== How to migrateAdapting existing code to use the `RestHighLevelClient` instead of the `TransportClient`requires the following steps:- Update dependencies- Update client initialization- Update application code=== Updating the dependenciesJava application that uses the `TransportClient` depends on the`org.elasticsearch.client:transport` artifact. This dependencymust be replaced by a new dependency on the high-level client.The <<java-rest-high-getting-started,Getting Started>> page shows typical configurations for Maven and Gradle and presents the <<java-rest-high-getting-started-dependencies, dependencies>> brought by the high-level client.=== Changing the client's initialization codeThe `TransportClient` is typically initialized as follows:[source,java]--------------------------------------------------Settings settings = Settings.builder()        .put("cluster.name", "prod").build();TransportClient transportClient = new PreBuiltTransportClient(settings)        .addTransportAddress(new TransportAddress(InetAddress.getByName("localhost"), 9300))        .addTransportAddress(new TransportAddress(InetAddress.getByName("localhost"), 9301));--------------------------------------------------The initialization of a `RestHighLevelClient` is different. It requires to providea <<java-rest-low-usage-initialization,low-level client builder>> as a constructorargument:["source","java",subs="attributes,callouts,macros"]--------------------------------------------------include-tagged::{doc-tests}/MainDocumentationIT.java[rest-high-level-client-init]--------------------------------------------------NOTE: The `RestClient` uses Elasticsearch's HTTP service which is bounded by default on `9200`. This port is different from the port used to connect to Elasticsearch with a `TransportClient`.The `RestHighLevelClient` is thread-safe. It is typically instantiated by theapplication at startup time or when the first request is executed.Once the `RestHighLevelClient` is initialized, it can be used to execute anyof the <<java-rest-high-supported-apis,supported APIs>>.As with the `TransportClient`, the `RestHighLevelClient` must be closed when itis not needed anymore or when the application is stopped.The code that closes the `TransportClient`:[source,java]--------------------------------------------------transportClient.close();--------------------------------------------------must be replaced with:["source","java",subs="attributes,callouts,macros"]--------------------------------------------------include-tagged::{doc-tests}/MainDocumentationIT.java[rest-high-level-client-close]--------------------------------------------------=== Changing the application's codeThe `RestHighLevelClient` supports the same request and response objectsas the `TransportClient`, but exposes slightly different methods tosend the requests.More importantly, the high-level client:- does not support request builders. The legacy methods like`client.prepareIndex()` must be changed to use request constructors like `new IndexRequest()` to create requests objects. The requests are then executed using synchronous or asynchronous dedicated methods like `client.index()` or `client.indexAsync()`.- does not provide indices or cluster management APIs. Managementoperations can be executed by external scripts or<<java-rest-high-level-migration-manage-indices, using the low-level client>>.==== How to migrate the way requests are builtThe Java API provides two ways to build a request: by using the request's constructor or by usinga request builder. Migrating from the `TransportClient` to the high-level client can bestraightforward if application's code uses the former, while changing usages of the latter canrequire more work.[[java-rest-high-level-migration-request-ctor]]===== With request constructorsWhen request constructors are used, like in the following example:["source","java",subs="attributes,callouts,macros"]--------------------------------------------------include-tagged::{doc-tests}/MigrationDocumentationIT.java[migration-request-ctor]--------------------------------------------------<1> Create an `IndexRequest` using its constructorThe migration is very simple. The execution using the `TransportClient`:[source,java]--------------------------------------------------IndexResponse response = transportClient.index(indexRequest).actionGet();--------------------------------------------------Can be easily replaced to use the `RestHighLevelClient`:["source","java",subs="attributes,callouts,macros"]--------------------------------------------------include-tagged::{doc-tests}/MigrationDocumentationIT.java[migration-request-ctor-execution]--------------------------------------------------[[java-rest-high-level-migration-request-builder]]===== With request buildersThe Java API provides a request builder for every type of request. They are exposed by the`TransportClient` through the many `prepare()` methods. Here are some examples:[source,java]--------------------------------------------------IndexRequestBuilder indexRequestBuilder   = transportClient.prepareIndex();  // <1>DeleteRequestBuilder deleteRequestBuilder = transportClient.prepareDelete(); // <2>SearchRequestBuilder searchRequestBuilder = transportClient.prepareSearch(); // <3>--------------------------------------------------<1> Create a `IndexRequestBuilder` using the `prepareIndex()` method from the `TransportClient`. Therequest builder encapsulates the `IndexRequest` to be executed.<2> Create a `DeleteRequestBuilder` using the `prepareDelete()` method from the `TransportClient`. Therequest builder encapsulates the `DeleteRequest` to be executed.<3> Create a `SearchRequestBuilder` using the `prepareSearch()` method from the `TransportClient`. Therequest builder encapsulates the `SearchRequest` to be executed.Since the Java High Level REST Client does not support request builders, applications that usethem must be changed to use <<java-rest-high-level-migration-request-ctor,requests constructors>> instead.NOTE: While you are incrementally migrating your application and you have both the transport clientand the high level client available you can always get the `Request` object from the `Builder` objectby calling `Builder.request()`. We do not advise continuing to depend on the builders in the long runbut it should be possible to use them during the transition from the transport client to the highlevel rest client.==== How to migrate the way requests are executedThe `TransportClient` allows to execute requests in both synchronous and asynchronous ways. This is alsopossible using the high-level client.===== Synchronous executionThe following example shows how a `DeleteRequest` can be synchronously executed using the `TransportClient`:[source,java]--------------------------------------------------DeleteRequest request = new DeleteRequest("index", "doc", "id"); // <1>DeleteResponse response = transportClient.delete(request).actionGet(); // <2>--------------------------------------------------<1> Create the `DeleteRequest` using its constructor<2> Execute the `DeleteRequest`. The `actionGet()` method blocks until aresponse is returned by the cluster.The same request synchronously executed using the high-level client is:["source","java",subs="attributes,callouts,macros"]--------------------------------------------------include-tagged::{doc-tests}/MigrationDocumentationIT.java[migration-request-sync-execution]--------------------------------------------------<1> Execute the `DeleteRequest`. The `delete()` method blocks until aresponse is returned by the cluster.===== Asynchronous executionThe following example shows how a `DeleteRequest` can be asynchronously executed using the `TransportClient`:[source,java]--------------------------------------------------DeleteRequest request = new DeleteRequest("index", "doc", "id"); // <1>transportClient.delete(request, new ActionListener<DeleteResponse>() { // <2>    @Override    public void onResponse(DeleteResponse deleteResponse) {        // <3>    }    @Override    public void onFailure(Exception e) {        // <4>    }});--------------------------------------------------<1> Create the `DeleteRequest` using its constructor<2> Execute the `DeleteRequest` by passing the request and a`ActionListener` that gets called on execution completion orfailure. This method does not block and returns immediately.<3> The `onResponse()` method is called when the response isreturned by the cluster.<4> The `onFailure()` method is called when an error occursduring the execution of the request.The same request asynchronously executed using the high-level client is:["source","java",subs="attributes,callouts,macros"]--------------------------------------------------include-tagged::{doc-tests}/MigrationDocumentationIT.java[migration-request-async-execution]--------------------------------------------------<1> Create the `DeleteRequest` using its constructor<2> Execute the `DeleteRequest` by passing the request and a`ActionListener` that gets called on execution completion orfailure. This method does not block and returns immediately.<3> The `onResponse()` method is called when the response isreturned by the cluster.<4> The `onFailure()` method is called when an error occursduring the execution of the request.[[java-rest-high-level-migration-manage-indices]]==== Manage Indices using the Low-Level REST ClientThe low-level client is able to execute any kind of HTTP requests, and cantherefore be used to call the APIs that are not yet supported by the high level client.For example, creating a new index with the `TransportClient` may look like this:[source,java]--------------------------------------------------Settings settings = Settings.builder() // <1>                                .put(SETTING_NUMBER_OF_SHARDS, 1)                                .put(SETTING_NUMBER_OF_REPLICAS, 0)                                .build();String mappings = XContentFactory.jsonBuilder()  // <2>                                .startObject()                                    .startObject("doc")                                        .startObject("properties")                                            .startObject("time")                                                .field("type", "date")                                            .endObject()                                        .endObject()                                    .endObject()                                .endObject()                                .string();CreateIndexResponse response = transportClient.admin().indices()  // <3>        .prepareCreate("my-index")        .setSettings(indexSettings)        .addMapping("doc", docMapping, XContentType.JSON)        .get();if (response.isAcknowledged() == false) {    // <4>}--------------------------------------------------<1> Define the settings of the index<2> Define the mapping for document of type `doc` using a`XContentBuilder`<3> Create the index with the previous settings and mappingusing the `prepareCreate()` method. The execution is synchronousand blocks on the `get()` method until the remote cluster returnsa response.<4> Handle the situation where the index has not been createdThe same operation executed with the low-level client could be:["source","java",subs="attributes,callouts,macros"]--------------------------------------------------include-tagged::{doc-tests}/MigrationDocumentationIT.java[migration-create-inded]--------------------------------------------------<1> Define the settings of the index<2> Define the body of the HTTP request using a `XContentBuilder` with JSON format<3> Include the settings in the request body<4> Include the mappings in the request body<5> Convert the request body from `String` to a `HttpEntity` andset its content type (here, JSON)<6> Execute the request using the low-level client. The execution is synchronousand blocks on the `performRequest()` method until the remote cluster returnsa response. The low-level client can be retrieved from an existing `RestHighLevelClient`instance through the `getLowLevelClient` getter method.<7> Handle the situation where the index has not been created[[java-rest-high-level-migration-cluster-health]]==== Checking Cluster Health using the Low-Level REST ClientAnother common need is to check the cluster's health using the Cluster API. Withthe `TransportClient` it can be done this way:[source,java]--------------------------------------------------ClusterHealthResponse response = client.admin().cluster().prepareHealth().get(); // <1>ClusterHealthStatus healthStatus = response.getStatus(); // <2>if (healthStatus != ClusterHealthStatus.GREEN) {    // <3>}--------------------------------------------------<1> Execute a `ClusterHealth` with default parameters<2> Retrieve the cluster's health status from the response<3> Handle the situation where the cluster's health is not greenWith the low-level client, the code can be changed to:["source","java",subs="attributes,callouts,macros"]--------------------------------------------------include-tagged::{doc-tests}/MigrationDocumentationIT.java[migration-cluster-health]--------------------------------------------------<1> Call the cluster's health REST endpoint using the default paramatersand gets back a `Response` object.<2> Retrieve an `InputStream` object in order to read the response's content<3> Parse the response's content using Elasticsearch's helper class `XContentHelper`. This helper requires the content type of the response to be passed as an argument and returns a `Map` of objects. Values in the map can be of any type, including inner `Map` that are used to represent the JSON object hierarchy.<4> Retrieve the value of the `status` field in the response map, casts it as a a `String`object and use the `ClusterHealthStatus.fromString()` method to convert it as a `ClusterHealthStatus`object. This method throws an exception if the value does not corresponds to a valid clusterhealth status.<5> Handle the situation where the cluster's health is not greenNote that for convenience this example uses Elasticsearch's helpers to parse the JSON responsebody, but any other JSON parser could have been use instead.=== Provide feedbackWe love to hear from you! Please give us your feedback about your migrationexperience and how to improve the Java High Level Rest Client on https://discuss.elastic.co/[our forum].
 |