Configuration des dépendances
Modifiez votre descripteur de construction Maven pour inclure le module ddeicated aux bases de recherche :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
<version>2.7.5</version>
</dependency>
Assignation des paramètres de connexion
Le service attend une adresse réseau via la configuration de l'application :
elasticsearch:
uri: localhost:9200
Création de la configuration du client
L'injection se fait en surchargeant la méthode abstraite fournie par le framework :
package com.tech.demo.configuration;
import lombok.Data;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.RestClients;
import org.springframework.data.elasticsearch.config.AbstractElasticsearchConfiguration;
@Data
@Configuration
public class SearchNodeInitializer extends AbstractElasticsearchConfiguration {
@Value("${elasticsearch.uri}")
private String networkEndpoint;
@Bean
@Override
public RestHighLevelClient searchClient() {
var config = ClientConfiguration.builder()
.connectedTo(networkEndpoint)
.build();
return RestClients.create(config).rest();
}
}
Modélisation de la donnée indexable
Définissez un objet supportant les annotations nécessaires au mappage :
package com.tech.demo.models;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
@Data
@Document(indexName = "user_catalog", createIndex = true)
public class IndexedProfile {
@Id
private Long identifier;
@Field(type = FieldType.Keyword)
private String fullName;
@Field(type = FieldType.Integer)
private Integer yearsActive;
@Field(type = FieldType.Text)
private String biography;
public IndexedProfile(Long identifier, String fullName, Integer yearsActive, String biography){
this.identifier = identifier;
this.fullName = fullName;
this.yearsActive = yearsActive;
this.biography = biography;
}
public IndexedProfile(){ }
}
Exposition des opérations CRUD
Implémentez un contrôleur REST pour piloter le stockage :
package com.tech.demo.api;
import com.tech.demo.models.IndexedProfile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.LinkedHashMap;
import java.util.Map;
@RestController
@RequestMapping("/management/items")
public class IndexManagementHandler {
@Autowired
private ElasticsearchOperations storageEngine;
@RequestMapping(value = "/retrieve")
public Map<string object=""> fetchAll() {
SearchHits<indexedprofile> results = storageEngine.search(Query.findAll(), IndexedProfile.class);
Map<string object=""> payload = new LinkedHashMap<>();
payload.put("success", true);
payload.put("entries", results.getSearchHits());
return payload;
}
@RequestMapping(value = "/store")
public Map<string object=""> persistNew() {
IndexedProfile profile = new IndexedProfile(1L, "Alice Martin", 29, "Ingénieure logicielle");
storageEngine.save(profile);
Map<string object=""> payload = new LinkedHashMap<>();
payload.put("success", true);
payload.put("message", "Item enregistré avec succès");
return payload;
}
@RequestMapping(value = "/modify")
public Map<string object=""> refreshExisting() {
IndexedProfile profile = new IndexedProfile(1L, "Bob Dupont", 31, "Chef de projet");
storageEngine.save(profile);
Map<string object=""> payload = new LinkedHashMap<>();
payload.put("success", true);
payload.put("message", "Données mises à jour");
return payload;
}
@RequestMapping(value = "/fetch/{identifier}")
public Map<string object=""> findById(@PathVariable Long identifier) {
IndexedProfile profile = storageEngine.get(identifier.toString(), IndexedProfile.class);
Map<string object=""> payload = new LinkedHashMap<>();
payload.put("success", true);
payload.put("record", profile);
return payload;
}
@RequestMapping(value = "/remove/{identifier}")
public Map<string object=""> deleteById(@PathVariable Long identifier) {
IndexedProfile target = new IndexedProfile();
target.setIdentifier(identifier);
String operationResult = storageEngine.delete(target);
Map<string object=""> payload = new LinkedHashMap<>();
payload.put("success", true);
payload.put("action_result", operationResult);
return payload;
}
@RequestMapping(value = "/purge")
public Map<string object=""> wipeAll() {
storageEngine.delete(Query.findAll(), IndexedProfile.class);
Map<string object=""> payload = new LinkedHashMap<>();
payload.put("success", true);
payload.put("status", "Index vidé");
return payload;
}
}</string></string></string></string></string></string></string></string></string></string></string></indexedprofile></string>
Résultats retournés
Appel vers /management/items/retrieve :
{
"success": true,
"entries": [
{
"index": "user_catalog",
"id": "1",
"score": 1.0,
"content": {
"identifier": 1,
"fullName": "Alice Martin",
"yearsActive": 29,
"biography": "Ingénieure logicielle"
}
}
]
}
Saisie via /management/items/fetch/1 :
{
"success": true,
"record": {
"identifier": 1,
"fullName": "Alice Martin",
"yearsActive": 29,
"biography": "Ingénieure logicielle"
}
}