Einführung in Spring Data Elasticsearch

1. Übersicht

In diesem Tutorial werden wir die Grundlagen von Spring Data Elasticsearch auf codeorientierte und praktische Weise untersuchen.

Wir zeigen, wie Sie Elasticsearch in einer Spring-Anwendung mithilfe von Spring Data Elasticsearch indizieren, suchen und abfragen. Spring Data Elasticseach ist ein Spring-Modul, das Spring Data implementiert und somit eine Möglichkeit bietet, mit der beliebten Open-Source-Suchmaschine auf Lucene-Basis zu interagieren.

Während Elasticsearch mit keinem kaum definierten Schema arbeiten kann, ist es üblich, eines zu entwerfen und Zuordnungen zu erstellen, die den Datentyp angeben, der in bestimmten Feldern zu erwarten ist . Wenn ein Dokument indiziert wird, werden seine Felder entsprechend ihrem Typ verarbeitet. Beispielsweise wird ein Textfeld gemäß den Zuordnungsregeln tokenisiert und gefiltert. Wir könnten auch eigene Filter und Tokenizer erstellen.

Der Einfachheit halber verwenden wir ein Docker-Image für unsere Elasticsearch-Instanz, obwohl jede Elasticsearch-Instanz, die Port 9200 überwacht, ausreicht .

Wir starten zunächst unsere Elasticsearch-Instanz:

docker run -d --name es762 -p 9200:9200 -e "discovery.type=single-node" elasticsearch:7.6.2

2. Federdaten

Spring Data hilft dabei, Boilerplate-Code zu vermeiden. Wenn wir beispielsweise eine Repository-Schnittstelle definieren, die die von Spring Data Elasticsearch bereitgestellte ElasticsearchRepository- Schnittstelle erweitert , werden CRUD-Operationen für die entsprechende Dokumentklasse standardmäßig verfügbar gemacht.

Darüber hinaus werden durch einfaches Deklarieren von Methoden mit Namen in einem vordefinierten Format Methodenimplementierungen für uns generiert - es ist nicht erforderlich, eine Implementierung der Repository-Schnittstelle zu schreiben.

Die Baeldung-Leitfäden zu Spring Data bieten die wichtigsten Informationen zum Einstieg in das Thema.

2.1. Maven-Abhängigkeit

Spring Data Elasticsearch bietet eine Java-API für die Suchmaschine. Um es zu verwenden, müssen wir der pom.xml eine neue Abhängigkeit hinzufügen :

 org.springframework.data spring-data-elasticsearch 4.0.0.RELEASE 

2.2. Repository-Schnittstellen definieren

Um neue Repositorys zu definieren, erweitern wir eine der bereitgestellten Repository-Schnittstellen und ersetzen die generischen Typen durch unsere tatsächlichen Dokument- und Primärschlüsseltypen.

Es ist wichtig zu beachten, dass sich ElasticsearchRepository von PagingAndSortingRepository erstreckt . Dies ermöglicht eine integrierte Unterstützung für Paginierung und Sortierung.

In unserem Beispiel verwenden wir die Paging-Funktion in unseren benutzerdefinierten Suchmethoden:

public interface ArticleRepository extends ElasticsearchRepository { Page findByAuthorsName(String name, Pageable pageable); @Query("{\"bool\": {\"must\": [{\"match\": {\"authors.name\": \"?0\"}}]}}") Page findByAuthorsNameUsingCustomQuery(String name, Pageable pageable); }

Mit der findByAuthorsName- Methode erstellt der Repository-Proxy eine Implementierung basierend auf dem Methodennamen. Der Auflösungsalgorithmus wird feststellen , dass es die für den Zugriff benötigt Autoren Eigenschaft und dann auf die Suche Name Eigenschaft der einzelnen Elemente.

Die zweite Methode, findByAuthorsNameUsingCustomQuery , verwendet eine benutzerdefinierte Elasticsearch boolean Abfrage, die definierte Verwendung @Query Anmerkung, die zwischen den Namen des Autors und dem vorgesehenen strenge Anpassung erfordert Namen Argument.

2.3. Java-Konfiguration

Bei der Konfiguration von Elasticsearch in unserer Java-Anwendung müssen wir definieren, wie wir eine Verbindung zur Elasticsearch-Instanz herstellen. Dafür verwenden wir einen RestHighLevelClient , der von der Elasticsearch-Abhängigkeit angeboten wird:

@Configuration @EnableElasticsearchRepositories(basePackages = "com.baeldung.spring.data.es.repository") @ComponentScan(basePackages = { "com.baeldung.spring.data.es.service" }) public class Config { @Bean public RestHighLevelClient client() { ClientConfiguration clientConfiguration = ClientConfiguration.builder() .connectedTo("localhost:9200") .build(); return RestClients.create(clientConfiguration).rest(); } @Bean public ElasticsearchOperations elasticsearchTemplate() { return new ElasticsearchRestTemplate(client()); } }

Wir verwenden eine standardmäßige Spring-fähige Annotation. Mit @EnableElasticsearchRepositories scannt Spring Data Elasticsearch das bereitgestellte Paket nach Spring Data-Repositorys.

Für die Kommunikation mit unserem Elasticsearch-Server verwenden wir einen einfachen RestHighLevelClient . Während Elasticsearch mehrere Arten von Clients bereitstellt, ist die Verwendung des RestHighLevelClient eine gute Möglichkeit, die Kommunikation mit dem Server zukunftssicher zu machen.

Schließlich haben wir eine ElasticsearchOperations- Bean eingerichtet, um Vorgänge auf unserem Server auszuführen. In diesem Fall instanziieren wir eine ElasticsearchRestTemplate .

3. Zuordnungen

Zuordnungen werden verwendet, um ein Schema für unsere Dokumente zu definieren. Indem wir ein Schema für unsere Dokumente definieren, schützen wir sie vor unerwünschten Ergebnissen wie der Zuordnung zu einem Typ, den wir nicht möchten.

Unsere Entität ist ein einfaches Dokument mit dem Namen Artikel, dessen ID vom Typ String ist . Wir legen außerdem fest, dass solche Dokumente in einem Index namens blog innerhalb des Artikeltyps gespeichert werden müssen .

@Document(indexName = "blog", type = "article") public class Article { @Id private String id; private String title; @Field(type = FieldType.Nested, includeInParent = true) private List authors; // standard getters and setters }

Indizes können verschiedene Typen haben. Wir können diese Funktion verwenden, um Hierarchien zu implementieren.

Das Autorenfeld ist als FieldType.Nested markiert . Dies ermöglicht es uns , die definieren Autor Klasse getrennt, aber die einzelnen Instanzen des Autors in einem eingebetteten haben Artikel Dokument , wenn es in Elasticsearch indiziert ist.

4. Indizieren von Dokumenten

Spring Data Elasticsearch erstellt im Allgemeinen automatisch Indizes basierend auf den Entitäten im Projekt. Wir können jedoch auch programmgesteuert einen Index über die Client-Vorlage erstellen:

elasticsearchTemplate.indexOps(Article.class).create();

Dann können wir dem Index Dokumente hinzufügen:

Article article = new Article("Spring Data Elasticsearch"); article.setAuthors(asList(new Author("John Smith"), new Author("John Doe"))); articleRepository.save(article);

5. Abfragen

5.1. Auf Methodennamen basierende Abfrage

Wenn wir die auf Methodennamen basierende Abfrage verwenden, schreiben wir Methoden, die die Abfrage definieren, die wir ausführen möchten. Während des Setups analysiert Spring Data die Methodensignatur und erstellt die Abfragen entsprechend:

String nameToFind = "John Smith"; Page articleByAuthorName = articleRepository.findByAuthorsName(nameToFind, PageRequest.of(0, 10));

Durch Aufrufen von findByAuthorsName mit einem PageRequest- Objekt erhalten wir die erste Ergebnisseite (die Seitennummerierung basiert auf Null), wobei diese Seite höchstens 10 Artikel enthält. Das Seitenobjekt liefert auch die Gesamtzahl der Treffer für die Abfrage zusammen mit anderen praktischen Paginierungsinformationen.

5.2. Eine benutzerdefinierte Abfrage

There are a couple of ways to define custom queries for Spring Data Elasticsearch repositories. One way is to use the @Query annotation, as demonstrated in section 2.2.

Another option is to use the query builder to create our custom query.

Having to search for articles that have the word “data” in the title, we could just create a NativeSearchQueryBuilder with a Filter on the title:

Query searchQuery = new NativeSearchQueryBuilder() .withFilter(regexpQuery("title", ".*data.*")) .build(); SearchHits articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog");

6. Updating and Deleting

In order to update a document, we first must retrieve it:

String articleTitle = "Spring Data Elasticsearch"; Query searchQuery = new NativeSearchQueryBuilder() .withQuery(matchQuery("title", articleTitle).minimumShouldMatch("75%")) .build(); SearchHits articles = elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog"); Article article = articles.getSearchHit(0).getContent();

Then, we can make changes to the document just by editing the content of the object using its assessors:

article.setTitle("Getting started with Search Engines"); articleRepository.save(article);

As for deleting, there are several options. We can retrieve the document and delete it using the delete method:

articleRepository.delete(article);

Wir können es auch nach ID löschen, wenn es bekannt ist:

articleRepository.deleteById("article_id");

Es ist auch möglich, benutzerdefinierte deleteBy- Abfragen zu erstellen und die von Elasticsearch angebotene Bulk- Löschfunktion zu verwenden:

articleRepository.deleteByTitle("title");

7. Fazit

In diesem Tutorial haben wir untersucht, wie Sie Spring Data Elasticsearch verbinden und verwenden können. Wir haben besprochen, wie wir Dokumente abfragen, aktualisieren und löschen können. Darüber hinaus haben wir auch erläutert, wie benutzerdefinierte Abfragen erstellt werden, die nicht zu den Angeboten von Spring Data Elasticsearch passen.

Wie üblich finden Sie den in diesem Tutorial verwendeten Quellcode auf GitHub.