Wprowadzenie do Spring Data Elasticsearch

1. Przegląd

W tym samouczku poznamy podstawy Spring Data Elasticsearch w praktyczny i skoncentrowany na kodzie sposób.

Pokażemy, jak indeksować, wyszukiwać i wysyłać zapytania do Elasticsearch w aplikacji Spring za pomocą Spring Data Elasticsearch. Spring Data Elasticseach to moduł Spring, który implementuje Spring Data, oferując w ten sposób sposób interakcji z popularną wyszukiwarką opartą na Lucene o otwartym kodzie źródłowym.

Chociaż Elasticsearch może działać bez trudno zdefiniowanego schematu, powszechną praktyką jest projektowanie go i tworzenie mapowań określających typ danych, których należy się spodziewać w niektórych polach . Kiedy dokument jest indeksowany, jego pola są przetwarzane zgodnie z ich typami. Na przykład pole tekstowe zostanie poddane tokenizacji i filtrowane zgodnie z regułami mapowania. Możemy również tworzyć własne filtry i tokenizery.

Dla uproszczenia użyjemy obrazu dockera dla naszej instancji Elasticsearch, chociaż wystarczy każda instancja Elasticsearch nasłuchująca na porcie 9200 .

Zaczynamy od odpalenia naszej instancji Elasticsearch:

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

2. Dane wiosenne

Spring Data pomaga uniknąć standardowego kodu. Na przykład, jeśli zdefiniujemy interfejs repozytorium, który rozszerzy interfejs ElasticsearchRepository dostarczony przez Spring Data Elasticsearch , operacje CRUD dla odpowiedniej klasy dokumentu zostaną domyślnie udostępnione.

Dodatkowo, po prostu deklarując metody z nazwami w predefiniowanym formacie, generowane są za nas implementacje metod - nie ma potrzeby pisania implementacji interfejsu repozytorium.

Poradniki Baeldung na temat Spring Data zawierają podstawowe informacje na temat rozpoczęcia tematu.

2.1. Zależność Mavena

Spring Data Elasticsearch udostępnia Java API dla wyszukiwarki. Aby z niego skorzystać, musimy dodać nową zależność do pom.xml :

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

2.2. Definiowanie interfejsów repozytorium

Aby zdefiniować nowe repozytoria, rozszerzamy jeden z udostępnionych interfejsów repozytoriów, zastępując typy ogólne naszymi rzeczywistymi typami dokumentów i kluczy podstawowych.

Należy zauważyć, że ElasticsearchRepository rozciąga się od PagingAndSortingRepository. Umożliwia to wbudowaną obsługę stronicowania i sortowania.

W naszym przykładzie użyjemy funkcji stronicowania w naszych niestandardowych metodach wyszukiwania:

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

Za pomocą metody findByAuthorsName proxy repozytorium utworzy implementację na podstawie nazwy metody. Algorytm rozstrzygania określi, że musi uzyskać dostęp do właściwości autorów, a następnie przeszuka właściwość name każdego elementu.

Druga metoda, findByAuthorsNameUsingCustomQuery , używa niestandardowego zapytania logicznego Elasticsearch, zdefiniowanego za pomocą adnotacji @Query , która wymaga ścisłego dopasowania między nazwiskiem autora a podanym argumentem nazwy .

2.3. Konfiguracja Java

Konfigurując Elasticsearch w naszej aplikacji Java, musimy zdefiniować sposób łączenia się z instancją Elasticsearch. W tym celu używamy RestHighLevelClient, który jest oferowany przez zależność Elasticsearch:

@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()); } }

Używamy standardowej adnotacji w stylu Spring. @EnableElasticsearchRepositories sprawi, że Spring Data Elasticsearch przeskanuje dostarczony pakiet w poszukiwaniu repozytoriów Spring Data.

Do komunikacji z naszym serwerem Elasticsearch używamy prostego RestHighLevelClient . Chociaż Elasticsearch zapewnia wiele typów klientów, użycie RestHighLevelClient jest dobrym sposobem na przyszłe zabezpieczenie komunikacji z serwerem.

Na koniec skonfigurowaliśmy bean ElasticsearchOperations do wykonywania operacji na naszym serwerze. W takim przypadku tworzymy wystąpienie ElasticsearchRestTemplate .

3. Mapowania

Mapowania służą do definiowania schematu naszych dokumentów. Definiując schemat naszych dokumentów, chronimy je przed niepożądanymi skutkami, takimi jak mapowanie na typ, którego nie chcielibyśmy.

Nasza encja to prosty dokument o nazwie Article, w którym identyfikator jest typu String . Określamy również, że takie dokumenty muszą być przechowywane w indeksie o nazwie blog w ramach typu artykułu .

@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 }

Indeksy mogą mieć kilka typów. Możemy użyć tej funkcji do implementacji hierarchii.

Pole autorów jest oznaczone jako FieldType.Nested . Dzięki temu możemy osobno zdefiniować klasę Author , ale indywidualne wystąpienia autora są osadzane w dokumencie Article, gdy jest on indeksowany w Elasticsearch.

4. Indeksowanie dokumentów

Spring Data Elasticsearch generalnie automatycznie tworzy indeksy na podstawie encji w projekcie. Jednak możemy również programowo utworzyć indeks za pomocą szablonu klienta:

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

Następnie możemy dodać dokumenty do indeksu:

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

5. Zapytania

5.1. Zapytanie oparte na nazwie metody

Kiedy używamy zapytania opartego na nazwie metody, piszemy metody definiujące zapytanie, które chcemy wykonać. Podczas konfiguracji Spring Data przeanalizuje sygnaturę metody i odpowiednio utworzy zapytania:

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

Wywołując findByAuthorsName z obiektem PageRequest , otrzymujemy pierwszą stronę wyników (numeracja stron od zera), która zawiera co najwyżej 10 artykułów. Obiekt strony podaje również całkowitą liczbę trafień dla zapytania wraz z innymi przydatnymi informacjami o paginacji.

5.2. Zapytanie niestandardowe

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);

Możemy również usunąć go po identyfikatorze, jeśli jest znany:

articleRepository.deleteById("article_id");

Możliwe jest również tworzenie niestandardowych zapytań deleteBy i korzystanie z funkcji usuwania zbiorczego oferowanej przez Elasticsearch:

articleRepository.deleteByTitle("title");

7. Wnioski

W tym samouczku zbadaliśmy, jak połączyć się i wykorzystać Spring Data Elasticsearch. Omówiliśmy, w jaki sposób możemy wyszukiwać, aktualizować i usuwać dokumenty. Ponadto omówiliśmy również, jak tworzyć niestandardowe zapytania i nie pasują one do tego, co oferuje Spring Data Elasticsearch.

Jak zwykle, kod źródłowy używany w tym samouczku można znaleźć na GitHub.