리타의 저장소

ES | Spring Boot에 Elasticsearch 연동하기 본문

Dev/Database

ES | Spring Boot에 Elasticsearch 연동하기

ريتا 2025. 12. 14. 22:44


 

스프링 프로젝트 생성하고 ES랑 연동하기

spring starter io에서 우선 프로젝트를 생성한다. 

생성할때, Spring Data Elasticsearch를 추가. 

그외 Lombok, JPA, PostgreSQL 등 기타 프로젝트에 필요한 설정도 추가해줬다.

 

자 그럼 users Document를 셋팅 해줘보자. (Spring -- Elasticsearch 연동)

* 주의 : 처음에는 그냥 실험하는 거니까 라는 마인드로 편의상 @Data 어노테이션을 사용한 코드를 업로드 했었으나, 다들 알다시피 실무에선 지양하는게 좋다. 그래서 그냥 바꿨다... 

UserDocument

package com.salary.backend;

import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;


@Getter
@NoArgsConstructor(access = lombok.AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
@Document(indexName = "users")
public class UserDocument {
    @Id
    private String id;

    @Field(type = FieldType.Keyword)
    private String name;

    @Field(type = FieldType.Long)
    private Long age;

    @Field(type = FieldType.Boolean)
    private Boolean isActive;


}

 

UserDocumentRepository

package com.salary.backend;

import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

public interface UserDocumentRepository extends ElasticsearchRepository<UserDocument, String> {
}

 

application.yml

yaml 파일에 es를 연결해준다.

spring:
  elasticsearch:
    uris: http://localhost:9200

logging:
  level:
    org.elasticsearch.client: TRACE

 

 

프로젝트 실행

그럼 이제 프로젝트를 실행을 시켜줘보자.

나 같은 경우, jpa를 넣어놓아서, Datasource를 exclude 해줘야 한다. Main 어플리 케이션에, exclude 처리 해주고 실행을 시켜보면

 

localhost 9200 / users 가 잘 떠있는걸 볼 수 있다.

지금은 기존에 Kibana에서 만들어놓은 users 때문에 한줄만 뜬다.

 

그럼 기존에 있던 users 를 삭제하고, 다시 spring boot application을 실행시켜 보자.

두줄이 뜨는데, 두번째 거는 PUT 이다. index가 생성된것이다.

Kibana에서 확인해보면, 잘 나오는 것을 확인할 수 있다.

 

CRUD API 만들기

1. user 등록

UserCreateRequestDto

package com.salary.backend;

import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class UserCreateRequestDto {

    private String id;
    private String name;
    private Long age;
    private Boolean isActive;

    public UserDocument toDocument() {
        return UserDocument.builder()
                .id(id)
                .name(name)
                .age(age)
                .isActive(isActive)
                .build();
    }
}

 

UserController에 PostMapping을 만들어줘보자

package com.salary.backend;

import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("users")
@RequiredArgsConstructor
public class UserController {
    private final UserDocumentRepository userDocumentRepository;

    @PostMapping
    public UserDocument createUser(@RequestBody UserCreateRequestDto requestDto) {
        return userDocumentRepository.save(requestDto.toDocument());
    }
}

 

Postman에서 post 요청 날려보기

 

Kibana에서 GET 해보면 잘 들어간 걸 볼 수 있다.

GET /users/_search

 

 

1. user 조회

UserController에 하단의 내용을 추가 해준다.

@GetMapping()
public Page<UserDocument> findUsers() {
    return userDocumentRepository.findAll(PageRequest.of(0, 10));
}

@GetMapping("{id}")
public UserDocument findUserById(@PathVariable String id) {
    return userDocumentRepository.findById(id).orElseThrow(() -> new RuntimeException("존재하지 않는 사용자입니다."));
}

 

postman에서 get 해보자.

id로 조회

 

잘된다.

 

3. user 수정

updateDto 추가

package com.salary.backend;

import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class UserUpdateRequestDto {

    private String name;
    private Long age;
    private Boolean isActive;

    public UserDocument applyTo(UserDocument origin) {
        return UserDocument.builder()
                .id(origin.getId())
                .name(name != null ? name : origin.getName())
                .age(age != null ? age : origin.getAge())
                .isActive(isActive != null ? isActive : origin.getIsActive())
                .build();
    }
}

 

usercontroller에 put 메서드 추가

// 수정 하기
@PutMapping("{id}")
public UserDocument updateUser(
        @PathVariable String id,
        @RequestBody UserUpdateRequestDto requestDto
) {
    UserDocument origin = userDocumentRepository.findById(id)
            .orElseThrow(() -> new RuntimeException("존재하지 않는 사용자입니다."));

    UserDocument updated = requestDto.applyTo(origin);
    return userDocumentRepository.save(updated);
}

 

Postman으로 확인해보자

잘 수정이 됐다.

조회해봐도 잘 수정이 되어있다.

 

4. user 삭제

// 삭제 하기
@DeleteMapping("/{id}")
public void deleteUser(@PathVariable String id) {
    UserDocument user = userDocumentRepository.findById(id).orElseThrow(() -> new RuntimeException("존재하지 않는 사용자입니다."));
    userDocumentRepository.delete(user);
}

 


 

CRUD를 메서드 만들어서 Spring - ES 연동해서 사용해보았다. 사실 뭐 내부적으로는 당연히 엄청 이런저런 규칙과 로직이 녹여질 수 있지만, NoSQL이든 SQL이든 모든 서비스의 근간은 역시 CRUD 인가보다.. 

 

사실 나중에 든 생각이지만, Elasticsearch를 사용하는 것은 둘째치고, 실 서비스에서 검색 품질을 생각하려면, 설계부분이 정말 매우 중요하다고 느꼈고, 혼자서는 할 수 없는 일이라는 것을 매우 매우 크게 느꼈다. 왜 검색팀이 있고 품질팀이 있는지,, 뼈저리게 느꼈달까... 

 

여튼,,, 오랜만에 복습하니까 또 새롭다.