저번 포스팅에서 도커(dcoker)를 통해 ELK를 실행시켰습니다. 이번에는 스프링부트에서 Elasticsearch로 간단한 검색 API를 구현하려고 해요.
먼저 Spring Boot에서 Elasticsearch와 통신하기 위해 필요한 의존성을 추가해야 합니다. spring-data-elasticsearch 라이브러리를 사용하여 Elasticesearch와 연동할 수 있어요 😊
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch'
implementation 'org.elasticsearch.client:elasticsearch-rest-client:8.10.0'
...
}
위에 의존성을 추가했으면, Spring Boot가 Elasticsearch 클러스터와 연결할 수 있도록 application.yml 파일에 설정을 추가해야 해요.
spring:
elasticsearch:
uris: localhost:9200
username: elastic
password: changeme
...
위에 설정은 Docker에서 실행 중인 Elasticsearch에 연결하도록 구성됩니다. 저는 Docker의. env 파일에서 아이디를 elastic, 비밀번호는 changeme로 설정하였기 때문에, 위와 같이 설정하면 되었습니다.
이제 Elasticesearch와 통신할 수 있도록 ElasticsearchConfig를 생성하여 설정해 줄 거예요.
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;
@Configuration
public class ElasticsearchConfig extends ElasticsearchConfiguration {
@Value("${spring.elasticsearch.username}")
private String username;
@Value("${spring.elasticsearch.password}")
private String password;
@Value("${spring.elasticsearch.uris}")
private String host;
@Override
public ClientConfiguration clientConfiguration() {
return ClientConfiguration.builder()
.connectedTo(host)
.withBasicAuth(username, password)
.build();
}
}
Spring Boot와 Elasticsearch 간의 통신을 설정하기 위해, ElasticsearchConfig 클래스를 생성했습니다. 이 클래스는 ElasticsearchConfiguration을 상속받아 Spring Boot에서 Elasticsearch 클러스터에 쉽게 연결할 수 있도록 합니다.
우선, ElasticsearchConfiguration을 상속한 이유는 Spring Boot가 제공하는 기본 Elasticsearch 클라이언트 설정을 커스터마이징 하기 위함입니다. Spring은 Elasticsearch와의 통신을 간편하게 처리할 수 있는 내장 클래스를 제공하는데, 이를 확장해 맞춤형 설정을 추가할 수 있습니다. 여기서 핵심 설정은 clientConfiguration() 메서드입니다. 이 메서드는 Elasticsearch 클러스터와의 연결을 정의해요. connectedTo(host)는 application.yml 파일에 정의한 호스트 주소(Elasticsearch 서버)를 사용해 연결을 설정하고, withBasicAuth(username, password)는 기본 인증을 추가하여 보안을 유지합니다. 즉, 클러스터에 연결할 때 필요한 인증 정보를 함께 제공하는 것입니다.
Entity
먼저, Log 엔티티는 Elasticsearch에 저장될 문서 구조를 정의합니다. @Document 어노테이션을 사용해 Elasticsearch 인덱스(logstash-*)와 연동되며, @Id는 문서의 고유 식별자 역할을 합니다. 이 엔티티는 Elasticsearch에서 데이터를 주고받는 구조로 message, timestamp 등의 필드를 포함합니다.
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
@Getter
@Setter
@Document(indexName = "logstash-*")
public class Log {
@Id
private String id;
private String message;
private String timestamp;
}
Repository
LogRepository는 ElasticsearchRepository를 상속받아, Elasticsearch와의 기본 CRUD 기능을 제공합니다. 이 리포지토리는 Log 엔티티와 연결되어 있으며, String 타입의 ID를 사용해 데이터를 관리합니다. Spring Data JPA와 유사한 방식으로 Elasticsearch의 데이터를 조회, 저장할 수 있습니다.
import org.homepage.parksangji.entity.Log;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface LogRepository extends ElasticsearchRepository<Log, String> {
}
Service
LogService는 비즈니스 로직을 처리하는 레이어입니다. LogRepository를 주입받아, Elasticsearch에서 로그 데이터를 조회하는 역할을 합니다. 여기서는 findAllLogs() 메서드를 통해 모든 로그 데이터를 조회하고 반환하는 기능을 제공합니다. 이 서비스는 컨트롤러와 리포지토리 사이에서 데이터를 처리하는 중간 역할을 합니다.
import org.homepage.parksangji.entity.Log;
import org.homepage.parksangji.repository.LogRepository;
import org.springframework.stereotype.Service;
@Service
public class LogService {
private final LogRepository logRepository;
public LogService(LogRepository logRepository) {
this.logRepository = logRepository;
}
public Iterable<Log> findAllLogs() {
return logRepository.findAll();
}
}
Controller
LogController는 API 엔드포인트를 제공하는 레이어이에요. /logs/getAll 경로로 GET 요청을 받으면, LogService의 findAllLogs() 메서드를 호출하여 모든 로그 데이터를 조회하고, 이를 API 응답으로 반환합니다. 이 컨트롤러를 통해 클라이언트가 Elasticsearch의 데이터를 API로 조회할 수 있습니다.
import org.homepage.parksangji.entity.Log;
import org.homepage.parksangji.service.LogService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/logs")
public class LogController {
private final LogService logService;
public LogController(LogService logService) {
this.logService = logService;
}
@GetMapping("/getAll")
public Iterable<Log> getAllLogs() {
return logService.findAllLogs();
}
}
다음 포스팅에서는 실제 데이터를 Elasticsearch에 추가하거나 삭제하는 방법을 알아보고, 더 세부적인 쿼리 방식과 최적화 방법에 대해 다뤄보려고 합니다. 앞으로 더욱 깊이 있는 Elasticsearch의 활용 방법을 탐구해 보겠습니다. 😚😚