Creating Spring Boot Search Service
In this part, we will build the core backend service responsible for processing search requests. The service will read keywords from PostgreSQL, create Elasticsearch indexes, use Redis caching, and provide autocomplete APIs for the React frontend.
Backend Architecture
React Client
|
|
Spring Boot Search API
|
|-------------------
| |
Redis Cache Elasticsearch
|
|
PostgreSQL DatabaseCreate Spring Boot Project
Create a Spring Boot project using Spring Initializr with Java 21 and Maven.
- Spring Web
- Spring Data JPA
- Spring Data Elasticsearch
- Spring Data Redis
- PostgreSQL Driver
- Lombok
Backend Folder Structure
search-service
src/main/java/com/example/search
├── controller
│ └── SearchController.java
│
├── service
│ ├── SearchService.java
│ └── ElasticIndexService.java
│
├── entity
│ └── Keyword.java
│
├── document
│ └── KeywordDocument.java
│
├── repository
│ ├── KeywordRepository.java
│ └── KeywordElasticRepository.java
│
└── config
├── RedisConfig.java
└── CorsConfig.javaapplication.yml Configuration
server:
port: 8080
spring:
datasource:
url: jdbc:postgresql://localhost:5432/searchdb
username: admin
password: admin123
jpa:
hibernate:
ddl-auto: update
data:
redis:
host: localhost
port: 6379
elasticsearch:
uris: http://localhost:9200Create Keyword Entity
PostgreSQL stores the master keyword data. Elasticsearch will later create a searchable index from this data.
package com.example.search.entity;
import jakarta.persistence.*;
import lombok.Data;
@Entity
@Data
@Table(name="keywords")
public class Keyword {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String keyword;
private Long popularity;
}Create Repository Layer
package com.example.search.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.search.entity.Keyword;
public interface KeywordRepository
extends JpaRepository<Keyword,Long>{
}Insert Sample Data
INSERT INTO keywords(keyword,popularity)
VALUES
('spring boot',90000),
('spring security',80000),
('spring cloud',70000),
('java tutorial',60000),
('react hooks',50000);Create Elasticsearch Document
Elasticsearch does not directly search PostgreSQL. We create a separate search document optimized for autocomplete.
package com.example.search.document;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
@Data
@Document(indexName="keyword_index")
public class KeywordDocument {
@Id
private String id;
private String keyword;
private Long popularity;
}Elasticsearch Repository
package com.example.search.repository;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import com.example.search.document.KeywordDocument;
public interface KeywordElasticRepository
extends ElasticsearchRepository<KeywordDocument,String>{
}Sync PostgreSQL Data to Elasticsearch
When the application starts, keyword data is copied from PostgreSQL into Elasticsearch.
@Service
public class ElasticIndexService {
private final KeywordRepository keywordRepository;
private final KeywordElasticRepository elasticRepository;
public void sync(){
keywordRepository.findAll()
.stream()
.map(k -> {
KeywordDocument doc=new KeywordDocument();
doc.setId(String.valueOf(k.getId()));
doc.setKeyword(k.getKeyword());
doc.setPopularity(k.getPopularity());
return doc;
})
.forEach(elasticRepository::save);
}
}Create Search Service
@Service
public class SearchService {
private final KeywordElasticRepository repository;
public List<KeywordDocument> search(String text){
return repository
.findByKeywordContainingIgnoreCase(text);
}
}Add Elasticsearch Search Method
List<KeywordDocument> findByKeywordContainingIgnoreCase(String keyword);Create Search Controller
@RestController
@RequestMapping("/api/search")
public class SearchController {
private final SearchService service;
@GetMapping
public List<KeywordDocument> search(
@RequestParam String q
){
return service.search(q);
}
}Add Redis Cache
Frequently searched terms should not hit Elasticsearch every time. Redis stores previous search responses.
@Service
public class SearchService {
private final RedisTemplate<String,Object> redis;
public Object search(String keyword){
String key="search:"+keyword;
Object cached=redis.opsForValue().get(key);
if(cached!=null){
return cached;
}
Object result=databaseSearch(keyword);
redis.opsForValue()
.set(key,result,Duration.ofMinutes(10));
return result;
}
}Testing Search API
GET http://localhost:8080/api/search?q=sprExpected Response
[
{
"keyword":"spring boot",
"popularity":90000
},
{
"keyword":"spring security",
"popularity":80000
}
]Backend Development Flow Completed
- Spring Boot REST API created
- PostgreSQL keyword storage created
- Elasticsearch indexing implemented
- Redis caching added
- Autocomplete API ready for React
Next Part
In the next part, we will build the analytics microservice using Kafka, implement search tracking, trending searches, popularity ranking and event-driven architecture.