Jest - Cliente Java do Elasticsearch
1. Introdução
Qualquer pessoa que já trabalhou comElasticsearch sabe que criar consultas usandoRESTful search API pode ser entediante e sujeito a erros.
Neste tutorial, veremosJest, um cliente HTTP Java para Elasticsearch. Enquanto Elasticsearch fornece seu próprio cliente Java nativo,Jest provides a more fluent API and easier interfaces to work with.
2. Dependência do Maven
A primeira coisa que precisamos fazer é importar oJest library em nosso POM:
io.searchbox
jest
6.3.1
The versioning for Jest follows that of the main Elasticsearch product. Isso ajuda a garantir a compatibilidade entre cliente e servidor.
Incluindo a dependência de Jest, oElasticsearch library correspondente será incluído como uma dependência transitiva.
3. Usando o Jest Client
Nesta seção, veremos como usar o cliente Jest para realizar tarefas comuns com Elasticsearch.
Para usar o cliente Jest, simplesmente criamos um objetoJestClient usandoJestClientFactory. These objects are expensive to create and are thread-safe, então vamos criar uma instância singleton que pode ser compartilhada em todo o nosso aplicativo:
public JestClient jestClient() {
JestClientFactory factory = new JestClientFactory();
factory.setHttpClientConfig(
new HttpClientConfig.Builder("http://localhost:9200")
.multiThreaded(true)
.defaultMaxTotalConnectionPerRoute(2)
.maxTotalConnection(10)
.build());
return factory.getObject();
}
Isso criará um cliente Jest conectado a um cliente Elasticsearch em execução localmente. Embora este exemplo de conexão seja trivial,Jest also has full support for proxies, SSL, authentication, and even node discovery.
A classeJestClient é genérica e possui apenas alguns métodos públicos. The main one we’ll use is execute, que leva uma instância da interfaceAction. O cliente Jest fornece várias classes de construtores para ajudar a criar ações diferentes que interagem com o Elasticsearch.
The result of all Jest calls is an instance of JestResult. Podemos verificar o sucesso chamandoisSucceeded. Para ações malsucedidas, podemos chamargetErrorMessage para obter mais detalhes:
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. Gerenciando índices
Para verificar se existe um índice, usamos a açãoIndicesExists:
JestResult result = jestClient.execute(new IndicesExists.Builder("employees").build())
Para criar um índice, usamos a açãoCreateIndex:
jestClient.execute(new CreateIndex.Builder("employees").build());
Isso criará um índice com as configurações padrão. Podemos substituir configurações específicas durante a criação do índice:
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 criar ou alterar aliases também é simples usando a açãoModifyAliases:
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. Criando documentos
O cliente Jest torna mais fácil indexar - ou criar - novos documentos usando a classe de açãoIndex. Documents in Elasticsearch are just JSON data, e há várias maneiras de passar dados JSON para o cliente Jest para indexação.
Para este exemplo, vamos usar um documento imaginário de funcionário:
{
"name": "Michael Pratt",
"title": "Java Developer",
"skills": ["java", "spring", "elasticsearch"],
"yearsOfService": 2
}
A primeira maneira de representar um documento JSON é usando JavaString. Embora possamos criar manualmente a string JSON, precisamos estar atentos à formatação adequada, chaves e caracteres de aspas que escapam.
Portanto, é mais fácil usar uma biblioteca JSON, comoJackson para construir nossa estrutura JSON e, em seguida, converter paraString:
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());
Também podemos usar JavaMap para representar dados JSON e passá-los para a açãoIndex:
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());
Finalmente, o cliente Jest pode aceitar qualquer POJO que represente o documento a ser indexado. Digamos que temos uma classeEmployee:
public class Employee {
String name;
String title;
List skills;
int yearsOfService;
}
Podemos passar uma instância desta classe diretamente para o construtorIndex:
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. Leitura de documentos
Existem duas maneiras principais de acessar um documento do Elasticsearch usando o cliente Jest. Primeiro, se soubermos o ID do documento, podemos acessá-lo diretamente usando a açãoGet:
jestClient.execute(new Get.Builder("employees", "17").build());
Para acessar o documento retornado, devemos chamar um dos vários métodosgetSource. Podemos obter o resultado como JSON bruto ou desserializar de volta para um DTO:
Employee getResult = jestClient.execute(new Get.Builder("employees", "1").build())
.getSourceAsObject(Employee.class);
A outra forma de acessar documentos é por meio de uma consulta de pesquisa, que é implementada no Jest com a açãoSearch.
Jest client supports the full Elasticsearch query DSL. Assim como as operações de indexação, as consultas são expressas como documentos JSON e existem várias maneiras de executar pesquisas.
Primeiro, podemos passar uma string JSON que representa a consulta de pesquisa. Como um lembrete, devemos tomar cuidado para garantir que a sequência seja escapada corretamente e seja JSON válido:
String search = "{" +
" \"query\": {" +
" \"bool\": {" +
" \"must\": [" +
" { \"match\": { \"name\": \"Michael Pratt\" }}" +
" ]" +
" }" +
" }" +
"}";
jestClient.execute(new Search.Builder(search).build());
Como na açãoIndex acima, poderíamos usar uma biblioteca como Jackson para construir nossa string de consulta JSON.
Além disso, também podemos usar a API de ação de consulta Elasticsearch nativa. A única desvantagem disso é que nosso aplicativo precisa depender deElasticsearch library completos.
Com a açãoSearch, os documentos correspondentes podem ser acessados usando os métodosgetSource. No entanto,Jest also provides the Hit class, which wraps the matching documents and provides metadata about the results. Usando a classeHit, podemos acessar metadados adicionais para cada resultado: pontuação, roteamento e resultados de explicação, para citar alguns:
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. Atualização de documentos
Jest fornece uma açãoUpdate simples para atualizar documentos:
employee.setYearOfService(3);
jestClient.execute(new Update.Builder(employee).index("employees").id("1").build());
Ele aceita as mesmas representações JSON da açãoIndex que vimos anteriormente, facilitando o compartilhamento de código entre as duas operações.
3.5. Exclusão de documentos
A exclusão de um documento de um índice é feita usando a açãoDelete. Requer apenas um nome de índice e ID do documento:
jestClient.execute(new Delete.Builder("17")
.index("employees")
.build());
4. Operações em massa
Jest client also supports bulk operations. Isso significa que podemos economizar tempo e largura de banda enviando várias operações juntas ao mesmo tempo.
Usando a açãoBulk, podemos combinar qualquer número de solicitações em uma única chamada. Podemos até combinar diferentes tipos de solicitações:
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. Operações assíncronas
Jest client also supports asynchronous operations, o que significa que podemos realizar qualquer uma das operações acima usando E / S sem bloqueio.
Para invocar uma operação de forma assíncrona, basta usar o métodoexecuteAsync do cliente:
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
}
});
Observe que além da ação (indexação neste caso), o fluxo assíncrono também requer umJestResultHandler. O cliente Jest irá chamar este objeto quando a ação for concluída. A interface possui dois métodos -completedefailed - que permitem tratar o sucesso ou o fracasso da operação, respectivamente.
6. Conclusão
Neste tutorial, vimos brevemente o cliente Jest, um cliente Java RESTful para Elasticsearch.
Embora tenhamos coberto apenas uma pequena parte de sua funcionalidade, está claro que Jest é um cliente Elasticsearch robusto. Suas classes fluentes de construtores e as interfaces RESTful facilitam o aprendizado, e seu suporte completo às interfaces do Elasticsearch o tornam uma alternativa capaz ao cliente nativo.
Como sempre, todos os exemplos de código no tutorial sãoover on GitHub.