Jest - Elasticsearch Java Client

1. Einleitung

Jeder, der mit Elasticsearch gearbeitet hat, weiß, dass das Erstellen von Abfragen mithilfe der RESTful-Such-API mühsam und fehleranfällig sein kann.

In diesem Tutorial sehen wir uns Jest an, einen HTTP-Java-Client für Elasticsearch. Während Elasticsearch einen eigenen nativen Java-Client bereitstellt , bietet Jest eine flüssigere API und einfachere Schnittstellen .

2. Maven-Abhängigkeit

Als erstes müssen wir die Jest-Bibliothek in unser POM importieren:

 io.searchbox jest 6.3.1 

Die Versionierung für Jest folgt der des Hauptprodukts von Elasticsearch . Dies hilft, die Kompatibilität zwischen Client und Server sicherzustellen.

Durch Einbeziehen der Jest-Abhängigkeit wird die entsprechende Elasticsearch-Bibliothek als transitive Abhängigkeit aufgenommen.

3. Verwenden des Jest-Clients

In diesem Abschnitt wird die Verwendung des Jest-Clients zum Ausführen allgemeiner Aufgaben mit Elasticsearch beschrieben.

Um den Jest-Client zu verwenden, erstellen wir einfach ein JestClient- Objekt mit der JestClientFactory . Die Erstellung dieser Objekte ist teuer und threadsicher. Daher erstellen wir eine Singleton-Instanz, die in unserer gesamten Anwendung gemeinsam genutzt werden kann:

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

Dadurch wird ein Jest-Client erstellt, der mit einem lokal ausgeführten Elasticsearch-Client verbunden ist. Während dieses Verbindungsbeispiel trivial ist, bietet Jest auch vollständige Unterstützung für Proxys, SSL, Authentifizierung und sogar Knotenerkennung .

Die JestClient- Klasse ist generisch und verfügt nur über eine Handvoll öffentlicher Methoden. Das wichtigste, das wir verwenden, ist execute , das eine Instanz der Action- Schnittstelle verwendet. Der Jest-Client bietet mehrere Builder-Klassen, mit denen Sie verschiedene Aktionen erstellen können, die mit Elasticsearch interagieren.

Das Ergebnis aller Jest-Aufrufe ist eine Instanz von JestResult . Wir können den Erfolg überprüfen, indem wir isSucceeded aufrufen . Bei erfolglosen Aktionen können wir getErrorMessage aufrufen , um weitere Details zu erhalten:

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. Indizes verwalten

Um zu überprüfen, ob ein Index vorhanden ist, verwenden wir die Aktion IndicesExists :

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

Um einen Index zu erstellen, verwenden wir die Aktion CreateIndex :

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

Dadurch wird ein Index mit Standardeinstellungen erstellt. Wir können bestimmte Einstellungen während der Indexerstellung überschreiben:

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

Das Erstellen oder Ändern von Aliasen ist mit der Aktion ModifyAliases ebenfalls einfach :

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. Dokumente erstellen

Der Jest-Client erleichtert das Indizieren oder Erstellen neuer Dokumente mithilfe der Index- Aktionsklasse. Dokumente in Elasticsearch sind nur JSON-Daten , und es gibt mehrere Möglichkeiten, JSON-Daten zur Indizierung an den Jest-Client zu übergeben.

In diesem Beispiel verwenden wir ein imaginäres Mitarbeiterdokument:

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

Die erste Möglichkeit, ein JSON-Dokument darzustellen, ist die Verwendung eines Java- Strings . Während wir die JSON-Zeichenfolge manuell erstellen können, müssen wir auf die richtige Formatierung, geschweifte Klammern und Anführungszeichen achten.

Daher ist es einfacher, eine JSON-Bibliothek wie Jackson zu verwenden, um unsere JSON-Struktur zu erstellen und dann in einen String zu konvertieren :

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

Wir können auch eine Java Map verwenden , um JSON-Daten darzustellen und diese an die Index- Aktion zu übergeben:

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

Schließlich kann der Jest-Client jedes POJO akzeptieren, das das zu indizierende Dokument darstellt. Angenommen, wir haben eine Mitarbeiterklasse :

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

Wir können eine Instanz dieser Klasse direkt an den Index Builder übergeben:

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. Dokumente lesen

Es gibt zwei Möglichkeiten, mit dem Jest-Client über Elasticsearch auf ein Dokument zuzugreifen. Wenn wir die Dokument-ID kennen, können wir mit der Aktion Get direkt darauf zugreifen :

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

Um auf das zurückgegebene Dokument zugreifen zu können, müssen wir eine der verschiedenen getSource- Methoden aufrufen . Wir können das Ergebnis entweder als unformatierten JSON erhalten oder es wieder in ein DTO deserialisieren:

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

Die andere Möglichkeit , Dokumente für den Zugriff unter Verwendung einer Suchabfrage, die in Jest mit dem implementiert Search Aktion.

Der Jest-Client unterstützt die vollständige Elasticsearch-Abfrage DSL . Genau wie bei Indizierungsvorgängen werden Abfragen als JSON-Dokumente ausgedrückt, und es gibt mehrere Möglichkeiten, Suchvorgänge durchzuführen.

Zunächst können wir eine JSON-Zeichenfolge übergeben, die die Suchabfrage darstellt. Zur Erinnerung, wir müssen darauf achten, dass die Zeichenfolge ordnungsgemäß maskiert und gültig ist. JSON:

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

Wie bei der obigen Index- Aktion können wir eine Bibliothek wie Jackson verwenden, um unsere JSON-Abfragezeichenfolge zu erstellen.

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.

Obwohl wir nur einen kleinen Teil seiner Funktionalität behandelt haben, ist klar, dass Jest ein robuster Elasticsearch-Client ist. Die fließenden Builder-Klassen und RESTful-Schnittstellen erleichtern das Erlernen und die vollständige Unterstützung der Elasticsearch-Schnittstellen machen es zu einer leistungsfähigen Alternative zum nativen Client.

Wie immer sind alle Codebeispiele im Tutorial auf GitHub beendet.