Récemment, j’ai écrit l’article « Pagination avec Spring Data Elasticsearch 4.4 », mais nous avons déjà de nouvelles versions de Spring Data Elasticsearch 5.0 et Spring Boot 3.0. Il y a plusieurs changements et problèmes que nous devons prendre en compte lors de la mise à niveau.
Le but de cet article est de mettre en évidence les changements lors de la mise à niveau du projet sat-elk avec ces technologies :
- Spring Data Elasticsearch 5.0.1
- Démarrage de printemps 3.0.2
- Recherche élastique 8.5.3
Changements clés
Dans cet article, vous apprendrez
- Comment configurer Elasticsearch 8.5.3
- Comment configurer Spring Data Elasticsearch 5.0 dans un projet
- Comment gérer la mise à niveau vers les dernières technologies
Recherche élastique
Notre objectif est d’avoir une application pour gérer les données via le Spring Data Elasticsearch dans Elasticsearch. Vous pouvez trouver plus de détails dans mon article initial « Introduction à Spring Data Elasticsearch 4.1 ». Ici, vous ne trouverez que les étapes de base avec les différences ou les modifications mises en évidence.
Vérifions d’abord les changements.
Changements
Le dernier article utilisait Spring Data Elasticsearch dans la version 4.4, mais la dernière version (au moment de la rédaction de cet article) est la version 5.0.1. Vous pouvez trouver tous les détails ici.
Nous devons garder à l’esprit la matrice de compatibilité qui contient les versions compatibles des principales technologies -> Spring framework, Spring Boot, Spring Data Release Train, Spring Data Elasticsearch, et bien sûr, Elasticsearch lui-même.
Nos versions sont pilotées par Spring Boot 3.0.2 et Spring Data Release Train 2022.0.1.
Configuration Docker
Le premier changement significatif dans l’utilisation elasticsearch
L’image Docker est le commutateur vers HTTPS par défaut au lieu du HTTP précédent. Les différences de configuration d’Elasticsearch (situées dans /usr/share/elasticsearch/config/
file) dans ces versions sont :elasticsearch.yml
Elasticsearch 7.17.8 :
cluster.name: "docker-cluster"
network.host: 0.0.0.0
Elasticsearch 8.5.3 :
cluster.name: "docker-cluster"
network.host: 0.0.0.0
# Enable security features
xpack.security.enabled: true
xpack.security.enrollment.enabled: true
# Enable encryption for HTTP API client connections, such as Kibana, Logstash, and Agents
xpack.security.http.ssl:
enabled: true
keystore.path: certs/http.p12
# Enable encryption and mutual authentication between cluster nodes
xpack.security.transport.ssl:
enabled: true
verification_mode: certificate
keystore.path: certs/transport.p12
truststore.path: certs/transport.p12
#----------------------- END SECURITY AUTO CONFIGURATION -------------------------
L’astuce précédente (voir la section « Désactiver XPack dans Elasticsearch » dans mon article précédent) ne fonctionne plus maintenant, probablement parce que c’était une sorte de solution de contournement. Par conséquent, nous devons désactiver correctement la sécurité X-Pack.
Suivons ces étapes pour configurer correctement Elasticsearch.
Réseau personnalisé
docker network create sat-elk-net
Recherche élastique
docker run -d --name sat-elasticsearch --net sat-elk-net -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e "xpack.security.enabled=false" elasticsearch:8.5.3
Note: Voir le -e "xpack.security.enabled=false"
paramètre supplémentaire pour désactiver HTTPS.
ElasticHQ
docker run -d --name sat-elastichq --net sat-elk-net -p 5000:5000 elastichq/elasticsearch-hq
Spring Data Elasticsearch
Toutes les notes/astuces de mise à niveau pour la version 5.0.x peuvent être trouvées ici.
Dépendance Maven
Nous utilisons le spring-boot-starter-data-elasticsearch
dépendance dans notre projet Maven (pom.xml
) comme démontré ci-dessous. Nous pouvons trouver la dernière version disponible dans le référentiel Maven Central.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
<version>3.0.2</version>
</dependency>
De plus, notre code dépend également du Spring MVC (pour exposer les points de terminaison REST) et du jackson.dataformat
Module CSV (pour lire les fichiers CSV). Nous devrions les ajouter à notre projet en tant que :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-csv</artifactId>
<version>2.14.1</version>
</dependency>
Client Elasticsearch
Un deuxième changement clé (après la configuration de l’image Elasticsearch Docker) représente un nouveau client Elasticsearch utilisé par Spring Data Elasticsearch. Jusqu’à présent, nous avons utilisé la configuration spring.elasticsearch.uris
dans application.properties
fichier, mais cela ne fonctionne pas maintenant.
On peut encore le réutiliser avec un petit ajustement comme :
spring:
elasticsearch:
rest:
uris: oxygen-arnost.ifs.dev.fra.aws.dbgcloud.io:9200
Note: Seul le protocole principal a été supprimé.
Pour le nouveau client Elasticsearch, nous devons ajouter un ElasticsearchClientConfig
classe où nous utilisons cette propriété de configuration comme :
@Configuration
public class ElasticsearchClientConfig extends ElasticsearchConfiguration {
@Value("${spring.elasticsearch.rest.uris}")
String connetionUrl;
@Override
public ClientConfiguration clientConfiguration() {
return ClientConfiguration.builder()
.connectedTo(connetionUrl)
.build();
}
}
Nous devons également ajouter un ElasticsearchClientConfigTest
tester pour cette classe afin de satisfaire Sonar.
@SpringBootTest
class ElasticsearchClientConfigTest {
@MockBean
CityRepository cityRepository;
@Autowired
ElasticsearchClientConfig elasticsearchClientConfig;
@Test
void clientConfiguration() {
assertThat(elasticsearchClientConfig.connetionUrl).contains("oxygen-arnost");
}
}
Modifications de SearchHitsImpl
Il y avait deux problèmes mineurs liés à notre utilisation de SearchHits
interface dans l’article précédent.
Interface modifiée de SearchHitsImpl
Depuis la version 5.0, le constructeur du SearchHitsImpl
la classe a été élargie avec un nouveau pointInTimeId
argument. Cela n’a aucun impact sur notre implémentation, car il n’a été utilisé que dans des tests qui ont finalement été supprimés.
Le changement n’est pas bien documenté, mais la définition peut être trouvée dans SearchHits
classer:
Lors d’une recherche avec un point dans le temps, la réponse contient une nouvelle valeur d’identifiant de point dans le temps.
Ne fonctionne pas la conversion de Jackson pour les agrégations
Depuis Spring Data Elasticsearch 5.0.1, le SearchHit
l’instance contient aggregations
attribut rempli (il était nul dans la version précédente).
Voir le résultat de Spring Data Elasticsearch 4.4.6 :
Et aussi de Spring Data Elasticsearch 5.0.1.
L’action de recherche elle-même fonctionne correctement. Le problème se produit lorsque nous essayons d’envoyer le SearchHits
résultat directement au client en tant que JSON. Spring ne contient aucun convertisseur pour le AggregationsContainer
classe et produit cette erreur :
2023-01-05T08:28:44.707+01:00 ERROR 6656 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.springframework.data.elasticsearch.client.elc.ElasticsearchAggregations]] with root cause
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.springframework.data.elasticsearch.client.elc.ElasticsearchAggregations and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: org.springframework.data.elasticsearch.core.SearchHitSupport$SearchPageImpl["searchHits"]->org.springframework.data.elasticsearch.core.SearchHitsImpl["aggregations"])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1306) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:408) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:53) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:30) ~[jackson-databind-2.14.1.jar:2.14.1]
...
at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]
Par conséquent, nous pouvons simplifier notre fonction de recherche avec la pagination comme suit :
- Supprimer les deux précédents
searchPage
etsearchHits
méthodes dansCityController
etCityService
. - Modifiez notre
search
méthode dans laCityService
comme:
@SuppressWarnings("unchecked")
public Page<City> search(String name, String country, String subcountry, Pageable pageable) {
return (Page<City>) unwrapSearchHits(searchPageFor(searchHits(name, country, subcountry, pageable), pageable));
}
De cette façon, nous obtenons une recherche dynamique avec pagination sans avoir à nous attaquer au SearchHits
problèmes liés.
La nouvelle mise en œuvre de la recherche dynamique peut être vérifiée sur http://localhost:8080/api/cities?name=be&country=Czech&subcountry=bohemia&size=5&sort=name,asc avec ce résultat :
{
"content": [
{
"id": "ePHmOIUBcEaiCL6qmck4",
"name": "Benešov",
"country": "Czech Republic",
"subcountry": "Central Bohemia",
"geonameid": 3079508
},
...
],
"pageable": {
"sort": {
"empty": false,
"sorted": true,
"unsorted": false
},
"offset": 0,
"pageSize": 5,
"pageNumber": 0,
"paged": true,
"unpaged": false
},
"last": true,
"totalElements": 3,
"totalPages": 1,
"size": 5,
"number": 0,
"sort": {
"empty": false,
"sorted": true,
"unsorted": false
},
"first": true,
"numberOfElements": 3,
"empty": false
}
Conclusion
Cet article a couvert la mise à niveau vers le dernier Spring Data Elasticsearch 5.0.1 avec Elasticsearch…