Hello everyone! In this post, we will show how to use Spring Boot with OpenSearch.
· Prerequisites
· Overview
∘ What is OpenSearch?
∘ Why use OpenSearch?
· OpenSearch Setup with Docker
· Getting Started
∘ Spring Data for OpenSearch
∘ Configuring OpenSearch in Spring Boot
∘ Document Object Mapping
∘ OpenSearch Repositories
∘ Service Layer
∘ Book Controller
· Testing
· Conclusion
· References
Prerequisites
This is the list of all the prerequisites:
- Spring Boot 3.2.4
- Maven 3.8.+
- Java 17
- Postman / insomnia or any other API testing tool.
- Docker / Docker compose installed
Overview
What is OpenSearch?
OpenSearch is a community-driven, open source search and analytics suite derived from open source Elasticsearch and Kibana,
with development led by Amazon Web Services. OpenSearch consists of a data store and search engine (OpenSearch), a visualization and user interface (OpenSearch Dashboards), and a server-side data collector (Data Prepper). Users can extend the functionality of OpenSearch with a selection of plugins that enhance search, analytics, observability, security, machine learning, and more.
Why use OpenSearch?
- It’s open-source and free to use.
- OpenSearch has a large and active community of developers who contribute to the project, provide support, and help identify and fix bugs.
- It offers horizontal and vertical scalability, which means that we can add more nodes to the cluster to handle increasing data volumes.
- Easy integration with other open-source tools like Logstash, OpenSearch Dashboards, and Beats.
- OpenSearch includes security features like SSL/TLS encryption, role-based access control, and audit logging.
- It supports a range of language clients such as Go, JavaScript, Python, Java, PHP, .NET, Hadoop, and more. Use these clients to build applications that integrate directly with OpenSearch.
OpenSearch Setup with Docker
There are many ways to install OpenSearch (OS, Docker, Helm, Tarball, RPM, Debian, Ansible playbook, Windows). For this demo, We’ll use Docker containers. We will create a docker-compose file containing all the instructions to run a single node of OpenSearch instance in development mode.
version: '3.7'
services:
opensearch:
image: opensearchproject/opensearch:latest
container_name: opensearch
environment:
discovery.type: single-node
node.name: opensearch
bootstrap.memory_lock: true
OPENSEARCH_JAVA_OPTS: "-Xms512m -Xmx512m"
OPENSEARCH_INITIAL_ADMIN_PASSWORD: "CBsZ6#9kHxb"
DISABLE_SECURITY_PLUGIN: false
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536 # maximum number of open files for the OpenSearch user, set to at least 65536 on modern systems
hard: 65536
volumes:
- opensearch-data:/usr/share/opensearch/data
ports:
- 9200:9200
- 9600:9600
networks:
- opensearch-net
opensearch-dashboards:
image: opensearchproject/opensearch-dashboards:latest
container_name: opensearch-dashboards
ports:
- 5601:5601
expose:
- "5601"
environment:
OPENSEARCH_HOSTS: '["https://opensearch:9200"]'
networks:
- opensearch-net
depends_on:
- opensearch
volumes:
opensearch-data:
networks:
opensearch-net:
driver: bridge
openSearch service is ready:
The OpenSearch dashboard is also ready.
Username: admin
Password: CBsZ6#9kHxb
Getting Started
We will create a simple Spring project from start.spring.io, with the following dependencies: Spring Web, Lombok, and Validation.
Spring Data for OpenSearch
The Spring Data OpenSearch project provides Spring Data compatible integration with the OpenSearch search engine. Key functional areas of Spring Data OpenSearch are a POJO-centric model for interacting with OpenSearch Documents and easily writing a Repository-style data access layer. This project is built on top of Spring Data Elasticsearch.
At the moment, Spring Data OpenSearch provides the possibility to use the RestHighLevelCLient to connect to OpenSearch clusters.
<dependency>
<groupId>org.opensearch.client</groupId>
<artifactId>spring-data-opensearch</artifactId>
<version>1.3.0</version>
</dependency>
To use Spring Boot 3.x auto configuration support:
<dependency>
<groupId>org.opensearch.client</groupId>
<artifactId>spring-data-opensearch-starter</artifactId>
<version>1.3.0</version>
</dependency>
We will use Spring Data OpenSearch with Spring Boot 3. For this, we may consider excluding the ElasticsearchDataAutoConfiguration configuration from autodiscovery.
@SpringBootApplication(exclude = {ElasticsearchDataAutoConfiguration.class})
public class SpringBootOpensearchApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootOpensearchApplication.class, args);
}
}
Configuring OpenSearch in Spring Boot
In the application.yml file, add OpenSearch connection settings :
opensearch:
uris: https://127.0.0.1:9200
username: admin
password: CBsZ6#9kHxb
spring:
jackson:
serialization:
INDENT_OUTPUT: true
Document Object Mapping
In OpenSearch, a document is a collection for the representation of an object in an index.
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Document(indexName = "book")
public class Book {
@Id
private String id;
@Field(type = FieldType.Text, name = "title")
private String title;
@Field(type = FieldType.Integer, name = "page")
private Integer page;
@Field(type = FieldType.Text, name = "isbn")
private String isbn;
@Field(type = FieldType.Text, name = "description")
private String description;
@Field(type = FieldType.Text, name = "language")
private String language;
@Field(type = FieldType.Double, name = "price")
private Double price;
}
@Document: Applied at the class level to indicate this class is a candidate for mapping to the database.@Id: Applied at the field level to mark the field used for identity purposes.@Field: Applied at the field level and defines properties of the field.
OpenSearch Repositories
In this story, we will use Repository interfaces. we are creating a BookRepository interface that implements ElasticsearchRepository.
@Repository
public interface BookRepository extends ElasticsearchRepository<Book, String> {
}
Service Layer
The BookRepository will inject the service layer implementation class (BookServiceImpl).
@Slf4j
@Service
public class BookServiceImpl implements BookService {
private final BookRepository repository;
public BookServiceImpl(BookRepository repository) {
this.repository = repository;
}
@Override
public List<Book> getAll() {
return StreamSupport.stream(
Spliterators.spliteratorUnknownSize(repository.findAll().iterator(), 0), false)
.toList();
}
@Override
public Book add(Book book) {
log.info("addBook : {} " , book );
return repository.save(book);
}
@Override
public Book getById(String id) {
return repository.findById(id).orElseThrow(() -> new DataNotFoundException("Book id not found"));
}
@Override
public Book update(Book book, String id) {
repository.findById(id)
.ifPresentOrElse(book1 -> {
book1.setTitle(book.getTitle());
book1.setIsbn(book.getIsbn());
book1.setDescription(book.getDescription());
book1.setLanguage(book.getLanguage());
book1.setPage(book.getPage());
book1.setPrice(book.getPrice());
repository.save(book1);
},() -> {throw new DataNotFoundException("Book id not found");});
return book;
}
@Override
public void deleteById(String id) {
repository.deleteById(id);
}
}
Book Controller
@RestController
@RequestMapping("/api")
@Slf4j
public class BookController {
private final BookService bookService;
public BookController(BookService bookService) {
this.bookService = bookService;
}
@GetMapping("/book")
public ResponseEntity<List<Book>> getAllBooks() {
return ResponseEntity.ok().body(bookService.getAll());
}
@PostMapping("/book")
@ResponseStatus(HttpStatus.CREATED)
public Book addBook(@RequestBody @Valid Book book) {
return bookService.add(book);
}
@DeleteMapping("/book/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public ResponseEntity<?> deleteBookById(@PathVariable String id){
bookService.deleteById(id);
return ResponseEntity.ok().body("Done");
}
@GetMapping("/book/{id}")
public ResponseEntity<Book> getBookById(@PathVariable("id") String id) {
return ResponseEntity.ok().body(bookService.getById(id));
}
@PutMapping("/book/{id}")
@ResponseStatus(HttpStatus.OK)
public ResponseEntity<Book> updateBook(@RequestBody Book book, @PathVariable String id) {
var updatedBook = bookService.update(book, id);
return ResponseEntity.ok().body(updatedBook);
}
}
Testing
Now we are all done with our code. We can run our application and test it.
- Create Book
- Get All Book
- Delete book
Let’s consult the records in the OpenSearch Dashboard.

Conclusion
We’ve built a simple Rest API with Spring Boot and OpenSearch.
The complete source code is available on GitHub.
You can reach out to me and follow me on Medium, Twitter, GitHub, Linkedln
Thanks for reading!




