Spring boot avec Java API Client pour créer et exécuter des requêtes dans Elasticsearch.
Spring boot avec ES Java API Client pour créer et exécuter des requêtes dans Elasticsearch.
Conditions préalables:
Connaissances en Java, Spring boot, Elasticsearch, Kibana.
Concept:
Le but de ce blog est de présenter une idée pour connecter, construire des requêtes et interroger Elasticsearch via des applications Java.
Qu’est-ce qu’Elasticsearch :
Elasticsearch est un moteur de recherche et d’analyse distribué, gratuit et ouvert pour tous les types de données, y compris textuelles, numériques, géospatiales, structurées et non structurées. Il s’agit du composant central d’Elastic Stack, une collection d’outils gratuits et ouverts pour l’ingestion, l’enrichissement, le stockage, l’analyse et la visualisation de données, et est connu pour ses API REST simples, sa nature distribuée, sa vitesse et son évolutivité.
Technologies utilisées :
- Recherche élastique 8.3.3
- Botte à ressort 2.7.2
- Java 1.8
- Client d’API Java Elasticsearch 7.17.5
- Maven
Les outils utilisés:
- Kibana 8.3.3
- Facteur
Remarque : Le blog se concentre uniquement sur une partie de l’opération CRUD. Cliquez ici pour le code source complet avec les opérations CRUD.
Structure du projet :
Étape 1: Créez une application de démarrage Spring à l’aide de Spring Initalizr et sélectionnez les dépendances comme indiqué dans l’instantané ci-dessous.
Étape 2: Ajoutez les dépendances supplémentaires indiquées dans le pom.xml fichier ci-dessous.
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.2</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.poc.es</groupId> <artifactId>elasticsearch-springboot</artifactId> <version>0.0.1-SNAPSHOT</version> <name>elasticsearch-springboot</name> <description>Demo project for integrating elasticsearch with springboot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>co.elastic.clients</groupId> <artifactId>elasticsearch-java</artifactId> <version>7.17.5</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.3</version> </dependency> <dependency> <groupId>jakarta.json</groupId> <artifactId>jakarta.json-api</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> <version>${project.parent.version}</version> </plugin> </plugins> </build> </project>
Étape 3: Configuration d’Elasticsearch dans l’application de démarrage Spring.
application.yml
elastic: index: employees es: hostname: localhost port: 9200 username: admin password: password
ESRestClient.java
package com.poc.es.elasticsearchspringboot.config; import co.elastic.clients.elasticsearch.ElasticsearchClient; import co.elastic.clients.json.jackson.JacksonJsonpMapper; import co.elastic.clients.transport.ElasticsearchTransport; import co.elastic.clients.transport.rest_client.RestClientTransport; import lombok.Getter; import lombok.Setter; import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CredentialsProvider; import org.apache.http.impl.client.BasicCredentialsProvider; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClientBuilder; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration @ConfigurationProperties("es") @Getter @Setter public class ESRestClient { private String hostName; private int port; private String username; private String password; @Bean public ElasticsearchClient getElasticSearchClient() { final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password)); RestClientBuilder builder = RestClient.builder(new HttpHost(hostName, port)) .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)); // Create the low-level client RestClient restClient = builder.build(); // Create the transport with a Jackson mapper ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper()); // And create the API client return new ElasticsearchClient(transport); } }
Étape 4: Créer un contrôleur de repos ESRestController.java
@Autowired private ESService esService; @PostMapping("/index/fetchWithMust") public ResponseEntity<List<Employee>> fetchEmployeesWithMustQuery(@RequestBody Employee employeeSearchRequest) throws IOException { List<Employee> employees = esService.fetchEmployeesWithMustQuery(employeeSearchRequest); return ResponseEntity.ok(employees); } @PostMapping("/index/fetchWithShould") public ResponseEntity<List<Employee>> fetchEmployeesWithShouldQuery(@RequestBody Employee employeeSearchRequest) throws IOException { List<Employee> employees = esService.fetchEmployeesWithShouldQuery(employeeSearchRequest); return ResponseEntity.ok(employees); }
Étape 5 : Créer un modèle Employé.java.
package com.poc.es.elasticsearchspringboot.model; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @JsonInclude(JsonInclude.Include.NON_NULL) public class Employee { private Long id; private String firstName; private String lastName; private String email; private String gender; private String jobTitle; private String phone; private Integer size; }
Étape 6 : Créer une interface ESService.java et ESServiceImpl.java.
@Service public class ESServiceImpl implements ESService { @Autowired private ESClientConnector esClientConnector; @Override public List<Employee> fetchEmployeesWithMustQuery(Employee employee) throws IOException { return esClientConnector.fetchEmployeesWithMustQuery(employee); } @Override public List<Employee> fetchEmployeesWithShouldQuery(Employee employee) throws IOException { return esClientConnector.fetchEmployeesWithShouldQuery(employee); } }
Étape 7 : Créer une classe de connecteur qui effectue des appels d’API Elasticsearch ESClientConnector.java.
@Value("${elastic.index}") private String index; @Autowired private ElasticsearchClient elasticsearchClient; public List<Employee> fetchEmployeesWithMustQuery(Employee employee) throws IOException { List<Query> queries = prepareQueryList(employee); SearchResponse<Employee> employeeSearchResponse = elasticsearchClient.search(req-> req.index(index) .size(employee.getSize()) .query(query-> query.bool(bool-> bool.must(queries))), Employee.class); return employeeSearchResponse.hits().hits().stream() .map(Hit::source).collect(Collectors.toList()); } public List<Employee> fetchEmployeesWithShouldQuery(Employee employee) throws IOException { List<Query> queries = prepareQueryList(employee); SearchResponse<Employee> employeeSearchResponse = elasticsearchClient.search(req-> req.index(index) .size(employee.getSize()) .query(query-> query.bool(bool-> bool.should(queries))), Employee.class); return employeeSearchResponse.hits().hits().stream() .map(Hit::source).collect(Collectors.toList()); } private List<Query> prepareQueryList(Employee employee) { Map<String, String> conditionMap = new HashMap<>(); conditionMap.put("firstName.keyword", employee.getFirstName()); conditionMap.put("lastName.keyword", employee.getLastName()); conditionMap.put("gender.keyword", employee.getGender()); conditionMap.put("jobTitle.keyword", employee.getJobTitle()); conditionMap.put("phone.keyword", employee.getPhone()); conditionMap.put("email.keyword", employee.getEmail()); return conditionMap.entrySet() .stream() .filter(entry->!ObjectUtils.isEmpty(entry.getValue())) .map(entry->QueryBuilderUtils.termQuery(entry.getKey(), entry.getValue())) .collect(Collectors.toList()); }
Étape 8 : Créer une interface Util pour créer des requêtes ES QueryBuilderUtils.java
package com.poc.es.elasticsearchspringboot.utils; import co.elastic.clients.elasticsearch._types.query_dsl.Query; import co.elastic.clients.elasticsearch._types.query_dsl.QueryVariant; import co.elastic.clients.elasticsearch._types.query_dsl.TermQuery; public interface QueryBuilderUtils { public static Query termQuery(String field, String value) { QueryVariant queryVariant = new TermQuery.Builder() .caseInsensitive(true) .field(field).value(value).build(); return new Query(queryVariant); } }
Appels d’API via Postman :
Récupérez les données d’Elasticsearch à l’aide de la clause MUST :
Journaux : Requête ES construite avec « DEVOIR » clause en Java
POST /employees/_search?typed_keys=true { "query": { "bool": { "must": [ { "term": { "jobTitle.keyword": { "value": "Senior Developer", "case_insensitive": true } } }, { "term": { "gender.keyword": { "value": "Female", "case_insensitive": true } } } ] } } }
Récupérez les données d’Elasticsearch à l’aide de la clause SHOULD :
Journaux : Requête ES construite avec « DEVRAIT » clause en Java
POST /employees/_search?typed_keys=true { "query": { "bool": { "should": [ { "term": { "jobTitle.keyword": { "value": "Senior Developer", "case_insensitive": true } } }, { "term": { "gender.keyword": { "value": "Female", "case_insensitive": true } } } ] } } }
URL Github du projet : https://github.com/sundharamurali/elasticsearch-springboot.git
Source link