Jest - Elasticsearch Java Client

1. Introduzione

Chiunque abbia lavorato con Elasticsearch sa che la creazione di query utilizzando l'API di ricerca RESTful può essere noiosa e soggetta a errori.

In questo tutorial, esamineremo Jest, un client Java HTTP per Elasticsearch. Mentre Elasticsearch fornisce il proprio client Java nativo, Jest fornisce un'API più fluida e interfacce più semplici con cui lavorare .

2. Dipendenza da Maven

La prima cosa che dobbiamo fare è importare la libreria Jest nel nostro POM:

 io.searchbox jest 6.3.1 

Il controllo delle versioni di Jest segue quello del prodotto principale Elasticsearch . Ciò aiuta a garantire la compatibilità tra client e server.

Includendo la dipendenza Jest, la libreria Elasticsearch corrispondente verrà inclusa come dipendenza transitiva.

3. Utilizzo di Jest Client

In questa sezione, vedremo come utilizzare il client Jest per eseguire attività comuni con Elasticsearch.

Per utilizzare il client Jest, creiamo semplicemente un oggetto JestClient utilizzando JestClientFactory . Questi oggetti sono costosi da creare e sono thread-safe , quindi creeremo un'istanza singleton che può essere condivisa in tutta la nostra applicazione:

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

Questo creerà un client Jest connesso a un client Elasticsearch in esecuzione localmente. Sebbene questo esempio di connessione sia banale, Jest ha anche il pieno supporto per proxy, SSL, autenticazione e persino rilevamento dei nodi .

La classe JestClient è generica e ha solo una manciata di metodi pubblici. Il principale che useremo è execute , che accetta un'istanza dell'interfaccia Action . Il client Jest fornisce diverse classi di builder per aiutare a creare diverse azioni che interagiscono con Elasticsearch.

Il risultato di tutte le chiamate Jest è un'istanza di JestResult . Possiamo verificare il successo chiamando isSucceeded . Per azioni non riuscite, possiamo chiamare getErrorMessage per ottenere maggiori dettagli:

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. Gestione degli indici

Per verificare se esiste un indice, utilizziamo l' azione IndicesExists :

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

Per creare un indice, usiamo l' azione CreateIndex :

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

Questo creerà un indice con le impostazioni predefinite. Possiamo sovrascrivere impostazioni specifiche durante la creazione dell'indice:

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

E anche la creazione o la modifica degli alias è semplice utilizzando l' azione 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. Creazione di documenti

Il client Jest semplifica l'indicizzazione o la creazione di nuovi documenti utilizzando la classe di azioni Index . I documenti in Elasticsearch sono solo dati JSON e ci sono diversi modi per passare i dati JSON al client Jest per l'indicizzazione.

Per questo esempio, utilizziamo un documento Employee immaginario:

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

Il primo modo per rappresentare un documento JSON è utilizzare una stringa Java . Anche se possiamo creare manualmente la stringa JSON, dobbiamo essere consapevoli della corretta formattazione, parentesi graffe e caratteri di virgolette di escape.

Pertanto, è più semplice utilizzare una libreria JSON come Jackson per creare la nostra struttura JSON e quindi convertirla in una stringa :

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

Possiamo anche utilizzare una Java Map per rappresentare i dati JSON e passarli all'azione 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());

Infine, il client Jest può accettare qualsiasi POJO che rappresenta il documento da indicizzare. Supponiamo di avere una classe Employee :

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

Possiamo passare un'istanza di questa classe direttamente al generatore di indici :

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. Lettura di documenti

Esistono due modi principali per accedere a un documento da Elasticsearch utilizzando il client Jest. Innanzitutto, se conosciamo l'ID del documento, possiamo accedervi direttamente utilizzando l' azione Ottieni :

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

Per accedere al documento restituito, dobbiamo chiamare uno dei vari metodi getSource . Possiamo ottenere il risultato come JSON non elaborato o deserializzarlo di nuovo in un DTO:

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

L'altro modo per accedere ai documenti è utilizzare una query di ricerca, implementata in Jest con l' azione Cerca .

Il client Jest supporta la query DSL completa di Elasticsearch . Proprio come le operazioni di indicizzazione, le query sono espresse come documenti JSON e ci sono diversi modi per eseguire le ricerche.

Innanzitutto, possiamo passare una stringa JSON che rappresenta la query di ricerca. Come promemoria, dobbiamo fare attenzione a garantire che la stringa sia correttamente sottoposta a escape e sia JSON valido:

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

Come con l' azione Index sopra, potremmo usare una libreria come Jackson per costruire la nostra stringa di query 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.

Sebbene abbiamo coperto solo una piccola parte delle sue funzionalità, è chiaro che Jest è un robusto client Elasticsearch. Le sue fluenti classi builder e le interfacce RESTful lo rendono facile da imparare e il suo pieno supporto per le interfacce Elasticsearch lo rende una valida alternativa al client nativo.

Come sempre, tutti gli esempi di codice nel tutorial sono finiti su GitHub.