
지금까지 한일
- 인덱스 적용하면서 스프링 검색을 사용했을때, 성능 최적화 테스트
기본 스프링 검색기능으로는 성능 최적화에 한계가 있다는 것을 저번 테스트로 확인했다.
이번에 elasticsearch 적용을 끝냈고 스프링 검색이랑 검색 성능에 차이가 있는지 비교하기 위해 테스트를 진행했다.
테스트 방법
- 인기 커뮤니티 사이트를 몇개 조사 결과 게시글 전체량이 몇십만건이었다. 그래서 랜덤 더미데이터를 50만건 만들어 테스트 진행 했다.
- 검색 검색 엔진 당 5개의 단어(“장미”,”히비스커스“,”부레“,”무궁화“,”식물“)를 5번씩 검색해서 나오는 시간을 측정하여 비교
- 나온 데이터를 바탕으로 성능차이를 비교하여 몇% 개선되었는지 확인한다.
더미데이터 생성
한글로 만들어진 더미데이터가 필요했다.
그래서 몇가지 키워드를 주고 랜덤으로 게시판을 생성 하도록 구현했다.
public class DummyBoardsGenerator {
private static final Random RANDOM = new Random();
// 형용사 및 식물 이름 배열
private static final String[] ADJECTIVES = {
"아름다운", "행복한", "감동적인", "환상적인", "자랑스러운", "눈부신", "특별한"
};
private static final String[] PLANT_NAMES = {
"장미꽃", "해바라기", "히비스커스", "부레옥잠", "무궁화"
};
private static final AtomicLong counter = new AtomicLong(1);
private static Long getNextId() {
return counter.getAndIncrement(); // 1씩 증가
}
// 랜덤으로 제목을 생성하는 메서드
public static String generateRandomKoreanTitle() {
String adjective = ADJECTIVES[RANDOM.nextInt(ADJECTIVES.length)];
String plantName = PLANT_NAMES[RANDOM.nextInt(PLANT_NAMES.length)];
return adjective + " " + plantName; // 예: "아름다운 장미꽃"
}
// 랜덤으로 콘텐츠를 생성하는 메서드
public static String generateRandomKoreanContent(String title) {
String adjective = ADJECTIVES[RANDOM.nextInt(ADJECTIVES.length)];
String plantName = PLANT_NAMES[RANDOM.nextInt(PLANT_NAMES.length)];
return "이 " + adjective + " " + plantName + " 라는 식물 " + title + "어떤건지 알려줘"; // 예: "이번 아름다운 장미꽃 행사에서는 아름다운 장미꽃을 즐기실 수 있습니다."
}
}
@Component
public class DummyDataLoader implements CommandLineRunner {
private final BoardRepository boardRepository;
private final UserRepository userRepository;
private final BoardSearchRepository boardSearchRepository;
// 생성자 주입
@Autowired
public DummyDataLoader(BoardRepository boardRepository, UserRepository userRepository, BoardSearchRepository boardSearchRepository) {
this.boardRepository = boardRepository;
this.userRepository = userRepository;
this.boardSearchRepository = boardSearchRepository;
}
@Override
@Transactional
public void run(String... args) throws Exception {
// 유저 하나 생성 (임의의 유저 데이터)
User user = new User("aaaa@email.com", "password", "name", UserRole.ROLE_USER);
userRepository.save(user);
// 더미 게시물 생성 및 배치 삽입
int batchSize = 2500; // 한 번에 삽입할 배치 크기
int totalBoards = 500000; // 총 게시물 개수
for (int i = 1; i <= totalBoards; i++) {
// 랜덤 데이터 생성
String title = DummyBoardsGenerator.generateRandomKoreanTitle(); // 랜덤 제목
String content = DummyBoardsGenerator.generateRandomKoreanContent(title); // 랜덤 콘텐츠
PublicStatus status = PublicStatus.ALL; // 게시물 공개 상태 설정 (예: ALL)
// 게시물 객체 생성
Board board = new Board(title, content, status, user);
// 배치 방식으로 삽입
boardRepository.save(board);
// Elasticsearch에 저장할 BoardDocument 생성
BoardDocument boardDocument = new BoardDocument(
board.getId(),
board.getTitle(),
board.getContent(),
"" // 이미지 URL은 아직 없으므로 빈 문자열로 설정, 필요시 추가할 수 있음
);
// Elasticsearch에 BoardDocument 저장
boardSearchRepository.save(boardDocument);
// 일정 배치 크기마다 flush
if (i % batchSize == 0) {
boardRepository.flush(); // 배치 삽입 후 DB에 반영
}
}
System.out.println(totalBoards + "개의 게시물이 배치 방식으로 삽입되었습니다.");
}
}
게시글 생성시 위 클래스에서 주어진 키워드를 가진 게시글을 랜덤으로 조합한다.
아래 DummyDataLoader 클래스에서 run 메서드를 통해 프로젝트를 실행할때 자동으로 50만건을 2500개씩 배치사이즈로 생성 해준 게시판을 DB와 elasticsearch에 넣어준다.

전부 만드는데 오래걸렸다.
10만건 만드는 테스트도 했는데, 10만건 만드는 시간의 5배보다 더 많은 시간이 걸렸다.
다음엔 나눠서 여러번 생성하는게 낫겠다는 생각을 했다.
테스트 결과
우선 "장미"를 검색해봤다.
스프링 검색 엔진

elasticsearch 검색 엔진

(검색 시간 단위 : ms)
| 스프링 검색 | 엘라스틱 서치 | |
| 1 | 651 | 79 |
| 2 | 421 | 39 |
| 3 | 425 | 44 |
| 4 | 415 | 45 |
| 5 | 385 | 38 |
게시판이라 검색항목이 제목, 본문 2개뿐이라 크게 차이 안날 줄 알았는데 50만건 정도에서 테스트하니 시간차이가 꽤났다.
그리고 프로젝트를 실행시키고 첫 검색이 시간이 걸리고 검색할 수록 시간이 줄어들어 안정적인 시간이 나오던데, 이는
데이터베이스가 쿼리 결과나 데이터를 메모리 캐시에 저장을 하기 때문이다.
그래서 다른 검색어도 검색할때 차이를 보기위해 껐다 켰다를 반복하여 테스트 진행 했다.
"히비스커스" 검색
(검색 시간 단위 : ms)
| 스프링검색 | 엘라스틱 | |
| 1 | 1201 | 182 |
| 2 | 438 | 99 |
| 3 | 449 | 93 |
| 4 | 405 | 91 |
| 5 | 400 | 88 |
단어 길이가 길어져 둘다 시간이 장미보다는 걸렸지만 어쨋든 두 검색엔진간에 차이가 꽤 난다는것을 알 수 있다.
나머지 단어 "부레,"무궁화","식물" 도 검색하여 데이터를 수집했다.
단어 별 검색 시간
스프링 검색 엔진
(검색 시간 단위 : ms)
| 장미 | 히비스커스 | 부레 | 무궁화 | 식물 | ||
| 시행 횟수 | 1 | 651 | 1201 | 690 | 791 | 790 |
| 2 | 421 | 438 | 420 | 401 | 408 | |
| 3 | 425 | 449 | 415 | 414 | 410 | |
| 4 | 415 | 405 | 411 | 426 | 437 | |
| 5 | 404 | 400 | 416 | 429 | 409 | |

elasticsearch 검색 엔진
(검색 시간 단위 : ms)
| 장미 | 히비스커스 | 부레 | 무궁화 | 식물 | ||
| 시행 횟수 | 1 | 79 | 182 | 144 | 133 | 54 |
| 2 | 39 | 99 | 105 | 74 | 35 | |
| 3 | 44 | 93 | 67 | 58 | 30 | |
| 4 | 45 | 91 | 59 | 56 | 27 | |
| 5 | 38 | 88 | 65 | 54 | 25 | |

결론
검색 엔진 평균 시간
검색엔진별 시행횟수 평균을 내서 차이를 계산하여 성능 개선률을 구해 보았다.
| 장미 | 히비스커스 | 부레 | 무궁화 | 식물 | |
| @Query | 415.8 | 424.2 | 415.6 | 415.4 | 418.4 |
| 엘라스틱서치 검색 | 42.2 | 91.6 | 62 | 60.6 | 29.2 |

두 검색엔진을 비교해보니 생각보다 차이가 컸고 개선 비율 계산 결과
약 86% 의 성능 개선이 있었다.
검색 필드가 작아서 차이가 날까 싶었지만 생각보다 차이가 많이 나서 신기했다.
동의어 검색도 성공하고 성능 개선도 확인해서 elasticsearch를 공부하고 적용한 보람이 있었다.
'java 배우기 > TIL' 카테고리의 다른 글
| Elasticsearch 동의어 필터 생성 중 오류 (2) | 2024.11.16 |
|---|---|
| 키바나에서 엘라스틱서치를 인식 못함. (1) | 2024.11.15 |
| 엘라스틱 서치 적용 하기 (0) | 2024.11.15 |
| 게시물 검색 최적화 작업 2-5 (인덱스 종합) (4) | 2024.11.08 |
| 게시물 검색 최적화 작업 2-4 (데이터 량 늘리기) (0) | 2024.11.08 |