1. Introduction
Anyone who has used Elasticsearch knows that building queries using the REST-based search API can be tedious and error-prone.
In this tutorial, we’ll explore Jest, an HTTP Java client for Elasticsearch. Elasticsearch offers its own native Java client, whereas Jest offers a smoother API and an easier interface to use.
2. Maven dependencies
The first thing we need to do is import the Jest library into our POM file:
<dependency> <groupId> IO. Searchbox </groupId> <artifactId>jest</artifactId> <version>6.3.1</version> </dependency>Copy the code
The Jest version follows the main version number of Elasticsearch. This ensures compatibility between client and server.
By including Jest dependencies, the corresponding [Elasticsearch library](search.maven.org/search?q=g:… A: ElasticSearch) will be included as a pass dependency.
3. Use Jest Client
In this section, we’ll explore how to use the Jest Client to perform common tasks in Elasticsearch.
To use JestClient, we simply create a JestClient object using JestClientFactory. These objects are expensive to create and thread-safe, so we’ll create a singleton instance that can be shared across the application:
public JestClient jestClient(a) {
JestClientFactory factory = new JestClientFactory();
factory.setHttpClientConfig(
new HttpClientConfig.Builder("http://localhost:9200")
.multiThreaded(true)
.defaultMaxTotalConnectionPerRoute(2)
.maxTotalConnection(10)
.build());
return factory.getObject();
}
Copy the code
Here you will create a Jest client that connects to Elasticsearch running locally. While this connection example is simple, Jest also fully supports proxies, SSL, authentication, and even node discovery.
The JestClient class is generic, with only a few public methods. One of the main methods we’ll use is execute, which takes an instance of the Action interface. The Jest client provides several builder classes to help create different operations that interact with Elasticsearch.
The result of all Jest calls is an instance of JestResult. We can check for success by calling the isSucceeded method. For failed operations, we can call the GetErrorMessage method to get more details:
JestResult jestResult = jestClient.execute(new Delete.Builder("1").index("employees").build());
if (jestResult.isSucceeded()) {
System.out.println("Success!");
}
else {
System.out.println("Error: " + jestResult.getErrorMessage());
}
Copy the code
3.1. Managing indexes
To check whether an index exists, we use IndicatesExists:
JestResult result = jestClient.execute(new IndicesExists.Builder("employees").build())
Copy the code
To create an index, we use CreateIndex:
jestClient.execute(new CreateIndex.Builder("employees").build());
Copy the code
This will create an index with default Settings. We can override specific Settings when creating an index:
Map<String, Object> settings = new HashMap<>();
settings.put("number_of_shards".11);
settings.put("number_of_replicas".2);
jestClient.execute(new CreateIndex.Builder("employees").settings(settings).build());
Copy the code
It is also easy to create or change an alias using the ModifyAliases operation:
jestClient.execute(new ModifyAliases.Builder(
new AddAliasMapping.Builder("employees"."e").build()).build());
jestClient.execute(new ModifyAliases.Builder(
new RemoveAliasMapping.Builder("employees"."e").build()).build());
Copy the code
3.2. Create documents
Jest Client makes it easy to manipulate class indexes or create new documents using indexes. Documents in Elasticsearch are just JSON data, and there are several ways to pass JSON data to the Jest Client for indexing.
For this example, let’s use a fictitious employee document:
{
"name": "Michael Pratt"."title": "Java Developer"."skills": ["java"."spring"."elasticsearch"]."yearsOfService": 2
}
Copy the code
The first way to represent JSON documents is to use Java strings. Although we can create JSON strings manually, we must pay attention to proper formatting, curly braces, and escape quote characters. Therefore, it is easier to use a JSON library (such as Jackson) to build our JSON structure and convert it to a string:
ObjectMapper mapper = new ObjectMapper();
JsonNode employeeJsonNode = mapper.createObjectNode()
.put("name"."Michael Pratt")
.put("title"."Java Developer")
.put("yearsOfService".2)
.set("skills", mapper.createArrayNode()
.add("java")
.add("spring")
.add("elasticsearch"));
jestClient.execute(new Index.Builder(employeeJsonNode.toString()).index("employees").build());
Copy the code
We can also use a Java Map to represent JSON data and pass it to an index operation:
Map<String, Object> employeeHashMap = new LinkedHashMap<>();
employeeHashMap.put("name"."Michael Pratt");
employeeHashMap.put("title"."Java Developer");
employeeHashMap.put("yearsOfService".2);
employeeHashMap.put("skills", Arrays.asList("java"."spring"."elasticsearch"));
jestClient.execute(new Index.Builder(employeeHashMap).index("employees").build());
Copy the code
Finally, the Jest Client can accept any POJO that represents the document to be indexed. Suppose we have an Employee class:
public class Employee {
String name;
String title;
List<String> skills;
int yearsOfService;
}
Copy the code
We can pass an instance of this class directly to the Index Builder:
Employee employee = new Employee();
employee.setName("Michael Pratt");
employee.setTitle("Java Developer");
employee.setYearsOfService(2);
employee.setSkills(Arrays.asList("java"."spring"."elasticsearch"));
jestClient.execute(new Index.Builder(employee).index("employees").build());
Copy the code
3.3. Read the document
There are two main ways to access documents from Elasticsearch using the Jest Client. First, if we know the document ID, we can access it directly using the GET operation:
jestClient.execute(new Get.Builder("employees"."17").build());
Copy the code
To access the returned document, we must call one of the getSource methods. We can get the result as raw JSON, or deserialize it to a DTO:
Employee getResult = jestClient.execute(new Get.Builder("employees"."1").build())
.getSourceAsObject(Employee.class);
Copy the code
Another way to access documents is to use search queries, which in Jest are implemented through search operations.
Jest Client supports the full Elasticsearch Query DSL. Like index operations, queries are represented as JSON documents, and there are multiple ways to perform the search.
First, we can pass a JSON string that represents the search query. As a reminder, we must ensure that strings are escaped correctly and are valid JSON:
String search = "{" +
" \"query\": {" +
" \"bool\": {" +
" \"must\": [" +
" { \"match\": { \"name\": \"Michael Pratt\" }}" +
"]" +
"}" +
"}" +
"}";
jestClient.execute(new Search.Builder(search).build());
Copy the code
As with the indexing operations above, we can use a library like Jackson to build JSON query strings. In addition, you can use the native Elasticsearch query manipulation API. One drawback to this is that our application must rely on the full Elasticsearch library.
We can use the getSource method to access the documents that match in the search operation. However, Jest also provides Hit classes that wrap matching documents and provide metadata about the results. Using the Hit class, we can access additional metadata for each result: score, route, and interpret the result, to name a few:
List<SearchResult.Hit<Employee, Void>> searchResults =
jestClient.execute(new Search.Builder(search).build())
.getHits(Employee.class);
searchResults.forEach(hit -> {
System.out.println(String.format("Document %s has score %s", hit.id, hit.score));
});
Copy the code
3.4. Update documentation
Jest provides a simple Update operation for updating documents:
employee.setYearOfService(3);
jestClient.execute(new Update.Builder(employee).index("employees").id("1").build());
Copy the code
It accepts the same JSON representation as the index operation we saw earlier, which makes it easy to share code between the two operations.
3.5. Delete documents
Deleting documents from the index is done using the Delete operation. It only needs the index name and document ID:
jestClient.execute(new Delete.Builder("17")
.index("employees")
.build());
Copy the code
4. Perform operations in batches
Jest Client also supports batch operations. This means that we can save time and bandwidth by sending multiple operations simultaneously.
With batch operations, we can combine any number of requests into a single invocation. We can even combine different types of requests:
jestClient.execute(new Bulk.Builder()
.defaultIndex("employees")
.addAction(new Index.Builder(employeeObject1).build())
.addAction(new Index.Builder(employeeObject2).build())
.addAction(new Delete.Builder("17").build())
.build());
Copy the code
5. Asynchronous operation
Jest Client also supports asynchronous operations. This means that we can perform any of the above operations using non-blocking I/O.
To invoke the operation asynchronously, simply use the executeAsync method on the client side:
jestClient.executeAsync(
new Index.Builder(employeeObject1).build(),
new JestResultHandler<JestResult>() {
@Override public void completed(JestResult result) {
// handle result
}
@Override public void failed(Exception ex) {
// handle exception}});Copy the code
Note that in addition to the (in this case, index) operation, the asynchronous flow also requires a JestResultHandler. When the operation is complete, the Jest Client calls the object. The interface has two methods – complete and fail – that allow handling the success or failure of the operation, respectively.
Conclusion 6.
In this tutorial, we briefly introduced Jest Client, a RESTful Java client for Elasticsearch. Although we’ve only covered a few of its features, it’s clear that Jest is a robust Elasticsearch client. Its smooth builder classes and RESTful interface make it easy to learn, and its full support for the Elasticsearch interface makes it a strong alternative to native clients.
As usual, all of the code examples in this tutorial are on our Github page.
Original: www.baeldung.com/elasticsear…
By Michael Pratt
Translator: huowolf /