본문 바로가기
카테고리 없음

Elasticsearch 활용한 검색 구현하기 - 2 (Springboot 연동)

by 은z 2025. 11. 14.

상황

 

앞선 포스팅에서는 엘라스틱 서치를 설치하는 작업을 해보았다.

2025.11.13 - [Back/Kotlin] - Elasticsearch 활용한 검색 구현하기 - 1 (Docker로 Elasticsearch + Kibana 구축)

 

이제는 Springboot + Kotlin을 활용하여 구현을 진행할 차례이다.

 

[개발환경]

 

  • Kotlin: 1.9.25
  • Java: 17
  • Spring Boot: 3.5.7

 


적용

 

✔️1. 세팅 및 설정파일 작성

1. build.gradle.kts에 의존성 추가

    implementation("org.springframework.boot:spring-boot-starter-data-elasticsearch")
Spring Data Elasticsearch는 Spring과 Elasticsearch를 쉽게 연동할 수 있도록 도와준다.

 

의존성 추가를 해주었으면, build 진행해준다.

 

2. 설정파일 작성

설치가 완료되고 나면 config를 작성한다.

 

2-1. resources 하위에 application.yml 작성한다.

 

📌논외지만, 참고!

  • src/main/kotlin/ : 실행 가능한 코드
  • src/main/resources/ : 코드가 사용하는 데이터 (설정, 이미지, HTML 등)

 

spring:
  elasticsearch:
    uris: http://localhost:9200
  data:
    elasticsearch:
      repositories:
        enabled: true

 

 

2.2 Elasticsearch 연결을 위한 Config Class 만들기

 

Spring Boot 3.x + Spring Data Elasticsearch 5.x 이상에서는 자동 설정이 강력해서 이 Config 클래스가 선택사항이다.

하지만, 추후에 SSL 설정, 타임아웃 설정등의 커스터마이징이 필요할 수 있으니 만들어두려고 한다.

(간단한 기본 설정만으로도 구현하고 싶다면, yml 파일만으로도 충분하다.)

import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Configuration
import org.springframework.data.elasticsearch.client.ClientConfiguration
import org.springframework.data.elasticsearch.client.elc.ElasticsearchConfiguration
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories

@Configuration
@EnableElasticsearchRepositories
class ElasticsearchConfig(
    @Value("\${spring.elasticsearch.uris}") private val host: String,
) : ElasticsearchConfiguration()  {

    override fun clientConfiguration(): ClientConfiguration {
        return ClientConfiguration.builder()
            .connectedTo(host.removePrefix("http://"))  // "localhost:9200"
//            .withConnectTimeout(Duration.ofSeconds(5))
//            .withSocketTimeout(Duration.ofSeconds(30))
            .build()
    }

}

 

 

 

✔️2. 실행 코드 작성

Entity

@Document(indexName = "products")
data class Product(
    @Id
    val id: String? = null,
    
    @Field(type = FieldType.Text)
    val name: String,
    
    @Field(type = FieldType.Text)
    val description: String,
    
    @Field(type = FieldType.Keyword)
    val category: String,
    
    @Field(type = FieldType.Double)
    val price: Double
)

 

Controller

@RestController
@RequestMapping("/api/products")
class ProductController(
    private val searchService: ProductSearchService
) {
    
    @PostMapping
    fun addProduct(@RequestBody product: Product): Product {
        return searchService.saveProduct(product)
    }
    
    @GetMapping("/search")
    fun search(@RequestParam keyword: String): List<Product> {
        return searchService.searchByKeyword(keyword)
    }
    
    @GetMapping
    fun getAll(): List<Product> {
        return searchService.getAllProducts()
    }
}

 

 

Service

@Service
class ProductSearchService(
    private val productRepository: ProductRepository,
    private val elasticsearchOperations: ElasticsearchOperations
) {
    
    fun saveProduct(product: Product): Product {
        return productRepository.save(product)
    }
    
    fun searchByKeyword(keyword: String): List<Product> {
        return productRepository.findByNameContaining(keyword)
    }
    
    fun searchWithCriteria(keyword: String): SearchHits<Product> {
        val criteria = Criteria.where("name").contains(keyword)
            .or("description").contains(keyword)
        
        val query = CriteriaQuery(criteria)
        return elasticsearchOperations.search(query, Product::class.java)
    }
    
    fun getAllProducts(): List<Product> {
        return productRepository.findAll().toList()
    }
}

 

Repository

@Repository
interface ProductRepository : ElasticsearchRepository<Product, String> {
    fun findByName(name: String): List<Product>
    fun findByNameContaining(keyword: String): List<Product>
    fun findByCategoryAndPriceLessThan(category: String, price: Double): List<Product>
}

 

 

✔️3. 실제 실행해보기

API 호출하여 작성한 코드가 정상 동작하는지 확인해보자.

나는 postman 을 이용해 테스트를 진행했다.

# 데이터 추가
curl -X POST http://localhost:8080/api/products \
  -H "Content-Type: application/json" \
  -d '{
    "name": "MacBook Pro",
    "description": "강력한 성능의 노트북",
    "category": "electronics",
    "price": 2500000
  }'

# 검색
curl "http://localhost:8080/api/products/search?keyword=MacBook"

 

오! 잘 된다!

 

 

✔️4. Kibana 접속해 데이터 확인해보기

http://localhost:5601 로 웹에서 접속하고, Analytics -> Discover -> Create Data View 순으로 이동한다.

 

Create data view 버튼을 누르면 products 인덱스가 생성되어있다!
그 후 name, index pattern(생성된 인덱스를 입력) Timestamp field를 설정한 후 view를 생성하면 생성된 데이터를 확인할 수 있다.

 

 

댓글