migration.asciidoc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. [[java-rest-high-level-migration]]
  2. == Migration Guide
  3. This section describes how to migrate existing code from the `TransportClient`
  4. to the Java High Level REST Client released with the version 5.6.0
  5. of Elasticsearch.
  6. === Motivations around a new Java client
  7. The 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].
  8. It is a special client as it uses the transport protocol to communicate with Elasticsearch,
  9. which causes compatibility problems if the client is not on the same version as the
  10. Elasticsearch instances it talks to.
  11. We released a low-level REST client in 2016, which is based on the well known Apache HTTP
  12. client and it allows to communicate with an Elasticsearch cluster in any version using HTTP.
  13. On top of that we released the high-level REST client which is based on the low-level client
  14. but takes care of request marshalling and response un-marshalling.
  15. If you're interested in knowing more about these changes, we wrote a blog post about the
  16. https://www.elastic.co/blog/state-of-the-official-elasticsearch-java-clients[state of the official Elasticsearch Java clients].
  17. === Prerequisite
  18. The Java High Level Rest Client requires Java `1.8` and can be used to send requests
  19. to an <<java-rest-high-compatibility,Elasticsearch cluster in a compatible version>>.
  20. === How to migrate
  21. Adapting existing code to use the `RestHighLevelClient` instead of the `TransportClient`
  22. requires the following steps:
  23. - Update dependencies
  24. - Update client initialization
  25. - Update application code
  26. === Updating the dependencies
  27. Java application that uses the `TransportClient` depends on the
  28. `org.elasticsearch.client:transport` artifact. This dependency
  29. must be replaced by a new dependency on the high-level client.
  30. The <<java-rest-high-getting-started,Getting Started>> page shows
  31. typical configurations for Maven and Gradle and presents the
  32. <<java-rest-high-getting-started-dependencies, dependencies>> brought by the
  33. high-level client.
  34. // This ID is bad but it is the one we've had forever.
  35. [[_changing_the_client_8217_s_initialization_code]]
  36. === Changing the client's initialization code
  37. The `TransportClient` is typically initialized as follows:
  38. [source,java]
  39. --------------------------------------------------
  40. Settings settings = Settings.builder()
  41. .put("cluster.name", "prod").build();
  42. TransportClient transportClient = new PreBuiltTransportClient(settings)
  43. .addTransportAddress(new TransportAddress(InetAddress.getByName("localhost"), 9300))
  44. .addTransportAddress(new TransportAddress(InetAddress.getByName("localhost"), 9301));
  45. --------------------------------------------------
  46. The initialization of a `RestHighLevelClient` is different. It requires to provide
  47. a <<java-rest-low-usage-initialization,low-level client builder>> as a constructor
  48. argument:
  49. ["source","java",subs="attributes,callouts,macros"]
  50. --------------------------------------------------
  51. include-tagged::{doc-tests}/MiscellaneousDocumentationIT.java[rest-high-level-client-init]
  52. --------------------------------------------------
  53. NOTE: The `RestClient` uses Elasticsearch's HTTP service which is
  54. bounded by default on `9200`. This port is different from the port
  55. used to connect to Elasticsearch with a `TransportClient`.
  56. The `RestHighLevelClient` is thread-safe. It is typically instantiated by the
  57. application at startup time or when the first request is executed.
  58. Once the `RestHighLevelClient` is initialized, it can be used to execute any
  59. of the <<java-rest-high-supported-apis,supported APIs>>.
  60. As with the `TransportClient`, the `RestHighLevelClient` must be closed when it
  61. is not needed anymore or when the application is stopped.
  62. The code that closes the `TransportClient`:
  63. [source,java]
  64. --------------------------------------------------
  65. transportClient.close();
  66. --------------------------------------------------
  67. must be replaced with:
  68. ["source","java",subs="attributes,callouts,macros"]
  69. --------------------------------------------------
  70. include-tagged::{doc-tests}/MiscellaneousDocumentationIT.java[rest-high-level-client-close]
  71. --------------------------------------------------
  72. // This ID is bad but it is the one we've had forever.
  73. [[_changing_the_application_8217_s_code]]
  74. === Changing the application's code
  75. The `RestHighLevelClient` supports the same request and response objects
  76. as the `TransportClient`, but exposes slightly different methods to
  77. send the requests.
  78. More importantly, the high-level client:
  79. - does not support request builders. The legacy methods like
  80. `client.prepareIndex()` must be changed to use
  81. request constructors like `new IndexRequest()` to create requests
  82. objects. The requests are then executed using synchronous or
  83. asynchronous dedicated methods like `client.index()` or `client.indexAsync()`.
  84. ==== How to migrate the way requests are built
  85. The Java API provides two ways to build a request: by using the request's constructor or by using
  86. a request builder. Migrating from the `TransportClient` to the high-level client can be
  87. straightforward if application's code uses the former, while changing usages of the latter can
  88. require more work.
  89. [[java-rest-high-level-migration-request-ctor]]
  90. ===== With request constructors
  91. When request constructors are used, like in the following example:
  92. ["source","java",subs="attributes,callouts,macros"]
  93. --------------------------------------------------
  94. include-tagged::{doc-tests}/MigrationDocumentationIT.java[migration-request-ctor]
  95. --------------------------------------------------
  96. <1> Create an `IndexRequest` using its constructor and id() setter.
  97. The migration is very simple. The execution using the `TransportClient`:
  98. [source,java]
  99. --------------------------------------------------
  100. IndexResponse response = transportClient.index(indexRequest).actionGet();
  101. --------------------------------------------------
  102. Can be easily replaced to use the `RestHighLevelClient`:
  103. ["source","java",subs="attributes,callouts,macros"]
  104. --------------------------------------------------
  105. include-tagged::{doc-tests}/MigrationDocumentationIT.java[migration-request-ctor-execution]
  106. --------------------------------------------------
  107. [[java-rest-high-level-migration-request-builder]]
  108. ===== With request builders
  109. The Java API provides a request builder for every type of request. They are exposed by the
  110. `TransportClient` through the many `prepare()` methods. Here are some examples:
  111. [source,java]
  112. --------------------------------------------------
  113. IndexRequestBuilder indexRequestBuilder = transportClient.prepareIndex(); // <1>
  114. DeleteRequestBuilder deleteRequestBuilder = transportClient.prepareDelete(); // <2>
  115. SearchRequestBuilder searchRequestBuilder = transportClient.prepareSearch(); // <3>
  116. --------------------------------------------------
  117. <1> Create a `IndexRequestBuilder` using the `prepareIndex()` method from the `TransportClient`. The
  118. request builder encapsulates the `IndexRequest` to be executed.
  119. <2> Create a `DeleteRequestBuilder` using the `prepareDelete()` method from the `TransportClient`. The
  120. request builder encapsulates the `DeleteRequest` to be executed.
  121. <3> Create a `SearchRequestBuilder` using the `prepareSearch()` method from the `TransportClient`. The
  122. request builder encapsulates the `SearchRequest` to be executed.
  123. Since the Java High Level REST Client does not support request builders, applications that use
  124. them must be changed to use <<java-rest-high-level-migration-request-ctor,requests constructors>> instead.
  125. NOTE: While you are incrementally migrating your application and you have both the transport client
  126. and the high level client available you can always get the `Request` object from the `Builder` object
  127. by calling `Builder.request()`. We do not advise continuing to depend on the builders in the long run
  128. but it should be possible to use them during the transition from the transport client to the high
  129. level rest client.
  130. ==== How to migrate the way requests are executed
  131. The `TransportClient` allows to execute requests in both synchronous and asynchronous ways. This is also
  132. possible using the high-level client.
  133. ===== Synchronous execution
  134. The following example shows how a `DeleteRequest` can be synchronously executed using the `TransportClient`:
  135. [source,java]
  136. --------------------------------------------------
  137. DeleteRequest request = new DeleteRequest("index", "doc", "id"); // <1>
  138. DeleteResponse response = transportClient.delete(request).actionGet(); // <2>
  139. --------------------------------------------------
  140. <1> Create the `DeleteRequest` using its constructor
  141. <2> Execute the `DeleteRequest`. The `actionGet()` method blocks until a
  142. response is returned by the cluster.
  143. The same request synchronously executed using the high-level client is:
  144. ["source","java",subs="attributes,callouts,macros"]
  145. --------------------------------------------------
  146. include-tagged::{doc-tests}/MigrationDocumentationIT.java[migration-request-sync-execution]
  147. --------------------------------------------------
  148. <1> Execute the `DeleteRequest`. The `delete()` method blocks until a
  149. response is returned by the cluster.
  150. ===== Asynchronous execution
  151. The following example shows how a `DeleteRequest` can be asynchronously executed using the `TransportClient`:
  152. [source,java]
  153. --------------------------------------------------
  154. DeleteRequest request = new DeleteRequest("index", "doc", "id"); // <1>
  155. transportClient.delete(request, new ActionListener<DeleteResponse>() { // <2>
  156. @Override
  157. public void onResponse(DeleteResponse deleteResponse) {
  158. // <3>
  159. }
  160. @Override
  161. public void onFailure(Exception e) {
  162. // <4>
  163. }
  164. });
  165. --------------------------------------------------
  166. <1> Create the `DeleteRequest` using its constructor
  167. <2> Execute the `DeleteRequest` by passing the request and a
  168. `ActionListener` that gets called on execution completion or
  169. failure. This method does not block and returns immediately.
  170. <3> The `onResponse()` method is called when the response is
  171. returned by the cluster.
  172. <4> The `onFailure()` method is called when an error occurs
  173. during the execution of the request.
  174. The same request asynchronously executed using the high-level client is:
  175. ["source","java",subs="attributes,callouts,macros"]
  176. --------------------------------------------------
  177. include-tagged::{doc-tests}/MigrationDocumentationIT.java[migration-request-async-execution]
  178. --------------------------------------------------
  179. <1> Create the `DeleteRequest` using its constructor
  180. <2> Execute the `DeleteRequest` by passing the request and a
  181. `ActionListener` that gets called on execution completion or
  182. failure. This method does not block and returns immediately.
  183. <3> The `onResponse()` method is called when the response is
  184. returned by the cluster.
  185. <4> The `onFailure()` method is called when an error occurs
  186. during the execution of the request.
  187. [[java-rest-high-level-migration-cluster-health]]
  188. ==== Checking Cluster Health using the Low-Level REST Client
  189. Another common need is to check the cluster's health using the Cluster API. With
  190. the `TransportClient` it can be done this way:
  191. [source,java]
  192. --------------------------------------------------
  193. ClusterHealthResponse response = client.admin().cluster().prepareHealth().get(); // <1>
  194. ClusterHealthStatus healthStatus = response.getStatus(); // <2>
  195. if (healthStatus != ClusterHealthStatus.GREEN) {
  196. // <3>
  197. }
  198. --------------------------------------------------
  199. <1> Execute a `ClusterHealth` with default parameters
  200. <2> Retrieve the cluster's health status from the response
  201. <3> Handle the situation where the cluster's health is not green
  202. With the low-level client, the code can be changed to:
  203. ["source","java",subs="attributes,callouts,macros"]
  204. --------------------------------------------------
  205. include-tagged::{doc-tests}/MigrationDocumentationIT.java[migration-cluster-health]
  206. --------------------------------------------------
  207. <1> Set up the request to wait for the cluster's health to become green if it isn't already.
  208. <2> Make the request and the get back a `Response` object.
  209. <3> Retrieve an `InputStream` object in order to read the response's content
  210. <4> Parse the response's content using Elasticsearch's helper class `XContentHelper`. This
  211. helper requires the content type of the response to be passed as an argument and returns
  212. a `Map` of objects. Values in the map can be of any type, including inner `Map` that are
  213. used to represent the JSON object hierarchy.
  214. <5> Retrieve the value of the `status` field in the response map, casts it as a `String`
  215. object and use the `ClusterHealthStatus.fromString()` method to convert it as a `ClusterHealthStatus`
  216. object. This method throws an exception if the value does not corresponds to a valid cluster
  217. health status.
  218. <6> Handle the situation where the cluster's health is not green
  219. Note that for convenience this example uses Elasticsearch's helpers to parse the JSON response
  220. body, but any other JSON parser could have been use instead.
  221. === Provide feedback
  222. We love to hear from you! Please give us your feedback about your migration
  223. experience and how to improve the Java High Level Rest Client on https://discuss.elastic.co/[our forum].