Spring Boot Integration with Elasticsearch
I. Introduction
In modern applications, search functionality is a crucial requirement. Open-source Elasticsearch has become the preferred full-text search engine due to its ability to quickly store, search, and analyze massive amounts of data. Spring Boot provides a convenient search function through Spring Data Elasticsearch, which integrates with Elasticsearch’s distributed search service based on the underlying Lucene.
II. Installation of Elasticsearch
To start with Elasticsearch, we use Docker to install it. We pull the Elasticsearch image using the command docker pull elasticsearch. To allocate 2G of memory, we use the command docker run -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -d -p 9200:9200 -p 9300:9300 --name es01 5c1e1ecfe33a. We can access the Elasticsearch instance at http://127.0.0.1:9200.
III. Understanding Elasticsearch Concepts
In Elasticsearch, a document is stored as an example, such as employee data. The data is stored in an index, which is a cluster of indices. Each index contains a plurality of types, and each type stores multiple documents with various attributes. The relationship between these concepts is similar to a database, where an index is like a database, a type is like a table, and a document is like a record in the table.
IV. Integration of Elasticsearch with Spring Boot
To integrate Elasticsearch with Spring Boot, we create a project called springboot-elasticsearch with web support. Spring Boot provides two ways to operate Elasticsearch: Jest and Spring Data. We will explore both methods.
Jest Operation with Elasticsearch
Jest is an Elasticsearch Java HTTP REST client. It fills the gaps in the official Elasticsearch Java API. We create a pom.xml file to manage dependencies, including Jest and Spring Boot Starter Data Elasticsearch.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gf</groupId>
<artifactId>springboot-elasticsearch</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springboot-elasticsearch</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>io.searchbox</groupId>
<artifactId>jest</artifactId>
<version>5.3.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
We create a Application.properties file to configure the Elasticsearch connection.
spring.elasticsearch.jest.uris=http://127.0.0.1:9200
We create an Article class to represent a document.
package com.gf.entity;
import io.searchbox.annotations.JestId;
import lombok.ToString;
@ToString
public class Article {
@JestId
private Integer id;
private String author;
private String title;
private String content;
// getters and setters
}
We create a test class to demonstrate Jest operation with Elasticsearch.
package com.gf;
import com.gf.entity.Article;
import io.searchbox.client.JestClient;
import io.searchbox.core.Index;
import io.searchbox.core.Search;
import io.searchbox.core.SearchResult;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.IOException;
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootElasticsearchApplicationTests {
@Autowired
private JestClient jestClient;
@Test
public void createIndex() {
// 1. Create an Article object
Article article = new Article();
article.setId(1);
article.setTitle("Good News");
article.setAuthor("Joe Smith");
article.setContent("Hello World");
// 2. Build an index
Index index = new Index.Builder(article)
.index("gf")
.type("news")
.build();
try {
// 3. Execute the index operation
jestClient.execute(index);
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void search() {
// 1. Create a search query
String query = "{\n" +
"\"Query\": {\n" +
"\"Match\": {\n" +
"\"Content\": \"hello\"\n" +
"}\n" +
"}\n" +
"}";
// 2. Build a search object
Search search = new Search.Builder(query)
.addIndex("gf")
.addType("news")
.build();
try {
// 3. Execute the search operation
SearchResult result = jestClient.execute(search);
System.out.println(result.getJsonString());
} catch (IOException e) {
e.printStackTrace();
}
}
}
Spring Data Operation with Elasticsearch
Spring Data Elasticsearch provides a more convenient way to interact with Elasticsearch. We create a Book class to represent a document.
package com.gf.entity;
import org.springframework.data.elasticsearch.annotations.Document;
import lombok.ToString;
@Document(indexName = "gf", type = "book")
@ToString
public class Book {
private Integer id;
private String bookName;
private String author;
// getters and setters
}
We create a BookRepository interface to define the repository operations.
package com.gf.repository;
import com.gf.entity.Book;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import java.util.List;
public interface BookRepository extends ElasticsearchRepository<Book, Integer> {
List<Book> findByBookNameLike(String bookName);
}
We create a test class to demonstrate Spring Data operation with Elasticsearch.
package com.gf;
import com.gf.entity.Article;
import com.gf.entity.Book;
import com.gf.repository.BookRepository;
import io.searchbox.client.JestClient;
import io.searchbox.core.Index;
import io.searchbox.core.Search;
import io.searchbox.core.SearchResult;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.IOException;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootElasticsearchApplicationTests {
@Autowired
private BookRepository bookRepository;
@Test
public void createIndex2() {
Book book = new Book();
book.setId(1);
book.setBookName("Journey to the West");
book.setAuthor("Wu Cheng-en");
bookRepository.index(book);
}
@Test
public void useFind() {
List<Book> list = bookRepository.findByBookNameLike("tour");
for (Book book : list) {
System.out.println(book);
}
}
}
However, we encounter an error due to the version conflict between Spring Data Elasticsearch and Elasticsearch. We refer to the official adaptation table provided by Spring Data Elasticsearch and find that we need to use version 6.2.2 of Spring Data Elasticsearch and version 6.5.1 of Elasticsearch.
We update our Docker image to use version 6.5.1 of Elasticsearch.
docker pull elasticsearch:6.5.1
docker run -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -d -p 9200:9200 -p 9300:9300 --name es02 5c1e1ecfe33a
We update our application.properties file to configure the Elasticsearch connection.
spring.data.elasticsearch.cluster-name=docker-cluster
spring.data.elasticsearch.cluster-nodes=127.0.0.1:9300
We test again and find that the test can be passed. We visit http://127.0.0.1:9200/gf/book/1 and can get the information into the index.