Перейти к основному содержимому

Введение в Spring Data Elasticsearch

· 6 мин. чтения

1. Обзор

В этом руководстве мы рассмотрим основы Spring Data Elasticsearch с акцентом на код и на практике.

Мы узнаем, как индексировать, искать и запрашивать Elasticsearch в приложении Spring, используя Spring Data Elasticsearch. Spring Data Elasticseach — это модуль Spring, который реализует Spring Data, предлагая способ взаимодействия с популярной поисковой системой с открытым исходным кодом на основе Lucene.

Хотя Elasticsearch может работать без четко определенной схемы, по-прежнему принято разрабатывать ее и создавать сопоставления, определяющие тип данных, которые мы ожидаем в определенных полях . Когда документ индексируется, его поля обрабатываются в соответствии с их типами. Например, текстовое поле будет размечено и отфильтровано в соответствии с правилами сопоставления. Мы также можем создавать собственные фильтры и токенизаторы.

Для простоты мы будем использовать образ докера для нашего экземпляра Elasticsearch, хотя подойдет любой экземпляр Elasticsearch, прослушивающий порт 9200 .

Мы начнем с запуска нашего экземпляра Elasticsearch:

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

2. Весенние данные

Spring Data помогает избежать шаблонного кода. Например, если мы определим интерфейс репозитория, расширяющий интерфейс ElasticsearchRepository , который предоставляет Spring Data Elasticsearch , операции CRUD для соответствующего класса документов станут доступны по умолчанию.

Кроме того, реализации методов будут генерироваться для нас просто путем объявления методов с именами в заранее определенном формате. Нет необходимости писать реализацию интерфейса репозитория.

Руководства ForEach по Spring Data предоставляют все необходимое для начала работы по этой теме.

2.1. Зависимость от Maven

Spring Data Elasticsearch предоставляет API Java для поисковой системы. Чтобы использовать его, нам нужно добавить новую зависимость в pom.xml :

<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>

2.2. Определение интерфейсов репозитория

Чтобы определить новые репозитории, мы расширим один из предоставленных интерфейсов репозитория, заменив общие типы нашими фактическими типами документов и первичных ключей.

Важно отметить, что ElasticsearchRepository расширяется от PagingAndSortingRepository. Это обеспечивает встроенную поддержку разбивки на страницы и сортировки.

В нашем примере мы будем использовать функцию пейджинга в наших пользовательских методах поиска:

public interface ArticleRepository extends ElasticsearchRepository<Article, String> {

Page<Article> findByAuthorsName(String name, Pageable pageable);

@Query("{\"bool\": {\"must\": [{\"match\": {\"authors.name\": \"?0\"}}]}}")
Page<Article> findByAuthorsNameUsingCustomQuery(String name, Pageable pageable);
}

При использовании метода findByAuthorsName прокси репозитория создаст реализацию на основе имени метода. Алгоритм разрешения определит, что ему необходимо получить доступ к свойству авторов , а затем выполнит поиск свойства имени каждого элемента.

Второй метод, findByAuthorsNameUsingCustomQuery , использует настраиваемый логический запрос Elasticsearch, определенный с помощью аннотации @Query , который требует строгого соответствия между именем автора и предоставленным аргументом имени .

2.3. Конфигурация Java

При настройке Elasticsearch в нашем Java-приложении нам нужно определить, как мы подключаемся к экземпляру Elasticsearch. Для этого мы будем использовать RestHighLevelClient, который предлагает зависимость Elasticsearch:

@Configuration
@EnableElasticsearchRepositories(basePackages = "com.foreach.spring.data.es.repository")
@ComponentScan(basePackages = { "com.foreach.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());
}
}

Мы используем стандартную аннотацию стиля с поддержкой Spring. @EnableElasticsearchRepositories заставит Spring Data Elasticsearch сканировать предоставленный пакет на наличие репозиториев Spring Data.

Для связи с нашим сервером Elasticsearch мы будем использовать простой RestHighLevelClient . Хотя Elasticsearch предоставляет несколько типов клиентов, использование RestHighLevelClient — это хороший способ обеспечить связь с сервером в будущем.

Наконец, мы настроим bean-компонент ElasticsearchOperations для выполнения операций на нашем сервере. В этом случае мы создаем экземпляр ElasticsearchRestTemplate .

3. Сопоставления

Мы используем сопоставления для определения схемы наших документов. Определяя схему для наших документов, мы защищаем их от нежелательных последствий, таких как сопоставление с нежелательным типом.

Наша сущность — это простой документ Article, где идентификатор имеет тип String . Мы также укажем, что такие документы должны храниться в индексе с именем blog внутри типа статьи .

@Document(indexName = "blog", type = "article")
public class Article {

@Id
private String id;

private String title;

@Field(type = FieldType.Nested, includeInParent = true)
private List<Author> authors;

// standard getters and setters
}

Индексы могут иметь несколько типов, которые мы можем использовать для реализации иерархий.

Мы пометим поле авторов как FieldType.Nested . Это позволяет нам определить класс Author отдельно, но по-прежнему иметь отдельные экземпляры author, встроенные в документ статьи , когда он индексируется в Elasticsearch.

4. Индексирование документов

Spring Data Elasticsearch обычно автоматически создает индексы на основе сущностей в проекте. Однако мы также можем создать индекс программно через клиентский шаблон:

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

Затем мы можем добавить документы в индекс:

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

5. Запрос

5.1. Запрос на основе имени метода

Когда мы используем запрос на основе имени метода, мы пишем методы, которые определяют запрос, который мы хотим выполнить. Во время установки Spring Data проанализирует сигнатуру метода и создаст соответствующие запросы:

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

Вызвав findByAuthorsName с объектом PageRequest , мы получим первую страницу результатов (нумерация страниц начинается с нуля), причем эта страница содержит не более 10 статей. Объект страницы также предоставляет общее количество совпадений для запроса, а также другую полезную информацию о разбиении на страницы.

5.2. Пользовательский запрос

Существует несколько способов определения пользовательских запросов для репозиториев Spring Data Elasticsearch. Один из способов — использовать аннотацию @Query , как показано в разделе 2.2.

Другой вариант — использовать конструктор запросов для создания нашего пользовательского запроса.

Если мы хотим искать статьи, в заголовке которых есть слово « данные », мы можем просто создать NativeSearchQueryBuilder с фильтром в заголовке:

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

6. Обновление и удаление

Чтобы обновить документ, мы должны сначала получить его:

String articleTitle = "Spring Data Elasticsearch";
Query searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchQuery("title", articleTitle).minimumShouldMatch("75%"))
.build();

SearchHits<Article> articles =
elasticsearchTemplate.search(searchQuery, Article.class, IndexCoordinates.of("blog");
Article article = articles.getSearchHit(0).getContent();

Затем мы можем внести изменения в документ, отредактировав содержимое объекта с помощью его асессоров:

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

Что касается удаления, то здесь есть несколько вариантов. Мы можем получить документ и удалить его с помощью метода удаления :

articleRepository.delete(article);

Мы также можем удалить его по идентификатору , как только мы его узнаем:

articleRepository.deleteById("article_id");

Также можно создавать пользовательские запросы на удаление и использовать функцию массового удаления, предлагаемую Elasticsearch :

articleRepository.deleteByTitle("title");

7. Заключение

В этой статье мы рассмотрели, как подключить и использовать Spring Data Elasticsearch. Мы обсудили, как запрашивать, обновлять и удалять документы. Наконец, мы научились создавать собственные запросы, если то, что предлагает Spring Data Elasticsearch, не соответствует нашим потребностям.

Как обычно, исходный код, использованный в этой статье, можно найти на GitHub .