Jest - Client Java Elasticsearch

1. Introduction

Quiconque a travaillé avec Elasticsearch sait que la création de requêtes à l'aide de leur API de recherche RESTful peut être fastidieuse et sujette aux erreurs.

Dans ce didacticiel, nous examinerons Jest, un client HTTP Java pour Elasticsearch. Alors qu'Elasticsearch fournit son propre client Java natif, Jest fournit une API plus fluide et des interfaces plus faciles à utiliser .

2. Dépendance de Maven

La première chose à faire est d'importer la bibliothèque Jest dans notre POM:

 io.searchbox jest 6.3.1 

La gestion des versions de Jest suit celle du produit principal Elasticsearch . Cela permet d'assurer la compatibilité entre le client et le serveur.

En incluant la dépendance Jest, la bibliothèque Elasticsearch correspondante sera incluse en tant que dépendance transitive.

3. Utilisation du client Jest

Dans cette section, nous examinerons l'utilisation du client Jest pour effectuer des tâches courantes avec Elasticsearch.

Pour utiliser le client Jest, nous créons simplement un objet JestClient à l'aide de JestClientFactory . Ces objets sont coûteux à créer et sont thread-safe , nous allons donc créer une instance singleton qui peut être partagée dans toute notre application:

public JestClient jestClient() { JestClientFactory factory = new JestClientFactory(); factory.setHttpClientConfig( new HttpClientConfig.Builder("//localhost:9200") .multiThreaded(true) .defaultMaxTotalConnectionPerRoute(2) .maxTotalConnection(10) .build()); return factory.getObject(); }

Cela créera un client Jest connecté à un client Elasticsearch exécuté localement. Bien que cet exemple de connexion soit trivial, Jest prend également en charge les proxies, SSL, l'authentification et même la découverte de nœuds .

La classe JestClient est générique et n'a qu'une poignée de méthodes publiques. Le principal que nous utiliserons est execute , qui prend une instance de l' interface Action . Le client Jest fournit plusieurs classes de générateur pour aider à créer différentes actions qui interagissent avec Elasticsearch.

Le résultat de tous les appels Jest est une instance de JestResult . Nous pouvons vérifier le succès en appelant isSucceeded . Pour les actions infructueuses, nous pouvons appeler getErrorMessage pour obtenir plus de détails:

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()); }

3.1. Gérer les indices

Pour vérifier si un index existe, nous utilisons l' action IndicesExists :

JestResult result = jestClient.execute(new IndicesExists.Builder("employees").build()) 

Pour créer un index, nous utilisons l' action CreateIndex :

jestClient.execute(new CreateIndex.Builder("employees").build());

Cela créera un index avec les paramètres par défaut. Nous pouvons remplacer des paramètres spécifiques lors de la création de l'index:

Map settings = new HashMap(); settings.put("number_of_shards", 11); settings.put("number_of_replicas", 2); jestClient.execute(new CreateIndex.Builder("employees").settings(settings).build());

Et créer ou modifier des alias est également simple à l'aide de l' action ModifyAliases :

jestClient.execute(new ModifyAliases.Builder( new AddAliasMapping.Builder("employees", "e").build()).build()); jestClient.execute(new ModifyAliases.Builder( new RemoveAliasMapping.Builder("employees", "e").build()).build());

3.2. Création de documents

Le client Jest facilite l'indexation - ou la création - de nouveaux documents à l'aide de la classe d'action Index . Les documents dans Elasticsearch ne sont que des données JSON , et il existe plusieurs façons de transmettre des données JSON au client Jest pour l'indexation.

Pour cet exemple, utilisons un document Employé imaginaire:

{ "name": "Michael Pratt", "title": "Java Developer", "skills": ["java", "spring", "elasticsearch"], "yearsOfService": 2 }

La première façon de représenter un document JSON consiste à utiliser une chaîne Java . Bien que nous puissions créer manuellement la chaîne JSON, nous devons faire attention au formatage, aux accolades et aux guillemets d'échappement appropriés.

Par conséquent, il est plus facile d'utiliser une bibliothèque JSON telle que Jackson pour créer notre structure JSON, puis la convertir en 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());

Nous pouvons également utiliser une carte Java pour représenter les données JSON et les transmettre à l' action Index :

Map 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());

Enfin, le client Jest peut accepter n'importe quel POJO qui représente le document à indexer. Disons que nous avons une classe Employee :

public class Employee { String name; String title; List skills; int yearsOfService; }

Nous pouvons passer une instance de cette classe directement au générateur d' index :

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());

3.3. Lecture de documents

Il existe deux manières principales d'accéder à un document depuis Elasticsearch à l'aide du client Jest. Premièrement, si nous connaissons l'ID du document, nous pouvons y accéder directement à l'aide de l' action Obtenir :

jestClient.execute(new Get.Builder("employees", "17").build());

Pour accéder au document retourné, nous devons appeler l'une des différentes méthodes getSource . Nous pouvons soit obtenir le résultat en tant que JSON brut, soit le désérialiser en un DTO:

Employee getResult = jestClient.execute(new Get.Builder("employees", "1").build()) .getSourceAsObject(Employee.class);

L'autre façon d'accéder aux documents consiste à utiliser une requête de recherche, qui est implémentée dans Jest avec l' action Rechercher .

Le client Jest prend en charge le DSL complet des requêtes Elasticsearch . Tout comme les opérations d'indexation, les requêtes sont exprimées sous forme de documents JSON, et il existe plusieurs façons d'effectuer des recherches.

Tout d'abord, nous pouvons transmettre une chaîne JSON qui représente la requête de recherche. Pour rappel, il faut veiller à ce que la chaîne soit correctement échappée et qu'elle soit valide JSON:

String search = "{" + " \"query\": {" + " \"bool\": {" + " \"must\": [" + " { \"match\": { \"name\": \"Michael Pratt\" }}" + " ]" + " }" + " }" + "}"; jestClient.execute(new Search.Builder(search).build());

Comme pour l' action Index ci-dessus, nous pourrions utiliser une bibliothèque telle que Jackson pour créer notre chaîne de requête JSON.

Additionally, we can also use the native Elasticsearch query action API. The one downside of this is that our application has to depend on the full Elasticsearch library.

With the Search action, the matching documents can be accessed using the getSource methods. However, Jest also provides the Hit class, which wraps the matching documents and provides metadata about the results. Using the Hit class, we can access additional metadata for each result: score, routing, and explain results, to name a few:

List
    
      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)); });
    

3.4. Updating Documents

Jest provides a simple Update action for updating documents:

employee.setYearOfService(3); jestClient.execute(new Update.Builder(employee).index("employees").id("1").build());

It accepts the same JSON representations as the Index action we saw earlier, making it easy to share code between the two operations.

3.5. Deleting Documents

Deleting a document from an index is done using the Delete action. It only requires an index name and document ID:

jestClient.execute(new Delete.Builder("17") .index("employees") .build());

4. Bulk Operations

Jest client also supports bulk operations. This means we can save time and bandwidth by sending multiple operations together at the same time.

Using the Bulk action, we can combine any number of requests into a single call. We can even combine different types of requests together:

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());

5. Asynchronous Operations

Jest client also supports asynchronous operations, which means we can perform any of the above operations using non-blocking I/O.

To invoke an operation asynchronously, simply use the executeAsync method of the client:

jestClient.executeAsync( new Index.Builder(employeeObject1).build(), new JestResultHandler() { @Override public void completed(JestResult result) { // handle result } @Override public void failed(Exception ex) { // handle exception } });

Note that in addition to the action (indexing in this case), the asynchronous flow also requires a JestResultHandler. The Jest client will call this object when the action has finished. The interface has two methods – completed and failed – that allow handling either success or failure of the operation, respectively.

6. Conclusion

In this tutorial, we have looked briefly at the Jest client, a RESTful Java client for Elasticsearch.

Bien que nous n'ayons couvert qu'une petite partie de ses fonctionnalités, il est clair que Jest est un client Elasticsearch robuste. Ses classes de construction fluides et ses interfaces RESTful le rendent facile à apprendre, et sa prise en charge complète des interfaces Elasticsearch en fait une alternative efficace au client natif.

Comme toujours, tous les exemples de code du didacticiel sont terminés sur GitHub.