Introduction
Elasticsearch is a powerful, open-source search and analytics engine that is built on top of Apache Lucene. It provides a fast, scalable, and distributed search solution, making it an ideal choice for e-commerce applications that require extensive search capabilities. In this article, we’ll explore how to integrate Elasticsearch with a Spring Boot application and implement detailed search, pagination, and custom filters using an e-commerce application as an example.
Prerequisites
Before we dive into the implementation, make sure you have the following installed on your system:
Java 8 or higher
Maven or Gradle
Elasticsearch 7.x
Setting up Elasticsearch
First, download and install Elasticsearch from the official website (https://www.elastic.co/downloads/elasticsearch). After installation, start Elasticsearch by running the following command in the terminal:
./bin/elasticsearch
Once Elasticsearch is up and running, verify it by accessing the following URL in your browser or by using a tool like Postman or curl:
http://localhost:9200
Integrating Elasticsearch with Spring Boot
To integrate Elasticsearch with Spring Boot, start by adding the following dependencies to your Maven or Gradle build file:
Maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
Gradle:
implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch'
Next, configure the Elasticsearch client in your application.properties
or application.yml
file:
spring.elasticsearch.rest.uris=http://localhost:9200
spring.elasticsearch.rest.username=elastic
spring.elasticsearch.rest.password=changeme
Creating an E-commerce Search API
4.1. Implementing Pagination
We’ll start by creating a Product
entity to represent the products in our e-commerce application. Add the @Document
annotation to the entity class to make it indexable by Elasticsearch:
import org.springframework.data.elasticsearch.annotations.Document;
@Document(indexName = "products")
public class Product {
// Product fields, getters, and setters
}
Next, create a ProductRepository
interface that extends ElasticsearchRepository
:
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
public interface ProductRepository extends ElasticsearchRepository<Product, String> {
}
Now, let’s create a ProductService
class to handle the search logic. We'll define a method named searchProducts
that accepts a search query, page number, and page size, and returns a paginated list of products:
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
public Page<Product> searchProducts(String query, int page, int size) {
Query searchQuery = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.queryStringQuery(query))
.withPageable(PageRequest.of(page, size))
.build();
return productRepository.search(searchQuery);
}
}
4.2. Adding Custom Filters
To implement custom filters, modify the searchProducts
method in the `ProductService
class to accept a list of filter conditions. We'll use Elasticsearch's BoolQueryBuilder
to combine multiple filters:
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
public Page<Product> searchProducts(String query, int page, int size, List<FilterCondition> filterConditions) {
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.queryStringQuery(query));
for (FilterCondition filterCondition : filterConditions) {
QueryBuilder filterQuery = QueryBuilders.rangeQuery(filterCondition.getField())
.gte(filterCondition.getMinValue())
.lte(filterCondition.getMaxValue());
boolQueryBuilder.filter(filterQuery);
}
Query searchQuery = new NativeSearchQueryBuilder()
.withQuery(boolQueryBuilder)
.withPageable(PageRequest.of(page, size))
.build();
return productRepository.search(searchQuery);
}
}
Create a FilterCondition
class to represent a filter condition:
public class FilterCondition {
private String field;
private Object minValue;
private Object maxValue;
// Getters and setters
}
Finally, create a REST API to expose the search functionality:
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping("/search")
public Page<Product> searchProducts(
@RequestParam("query") String query,
@RequestParam("page") int page,
@RequestParam("size") int size,
@RequestParam("filters") List<FilterCondition> filters) {
return productService.searchProducts(query, page, size, filters);
}
}
Now, you can search for products with pagination and custom filters by sending a GET request to the /search
endpoint with the appropriate query parameters.
Conclusion
In this article, we demonstrated how to integrate Elasticsearch with a Spring Boot application to create a powerful e-commerce search API. We implemented pagination and custom filters using Elasticsearch’s Query DSL, providing a flexible and scalable search solution for e-commerce applications. With this approach, you can deliver a better user experience by allowing users to quickly find and filter products according to their preferences.