🔄 리팩토링 대상
[검색 도메인]
: Board.sevice/ getallBoards, getBoardByCategory
- 태그에 대한 검색 요청이 없을때도 불필요한 조인이 발생
- 페이지 전체 수를 반환을 위해 쿼리가 한번 더 발생하는데 이부분에 대한 확인이 필요
- 검색기능에서 내용이 저는똑똑한개발자문선민입니다 라는 내용에서 똑똑한문선민이라고 검색하면 찾지못함
// 전체 게시물 조회
public Page<BoardResponseDto> getAllBoard(Pageable pageable, List<String> tagNames, String contents) {
QBoard board = QBoard.board;
QTagBoard tagBoard = QTagBoard.tagBoard;
BooleanBuilder builder = buildDynamicQuery(tagNames, contents, null);
return fetchBoards(pageable, builder);
}
// 카테고리별 게시물 조회
public Page<BoardResponseDto> getBoardByCategory(Pageable pageable, List<String> tagNames,
String contents,Long categoryId ) {
QBoard board = QBoard.board;
QTagBoard tagBoard = QTagBoard.tagBoard;
BooleanBuilder builder = buildDynamicQuery(tagNames, contents, categoryId);
return fetchBoards(pageable, builder);
}
private BooleanBuilder buildDynamicQuery(List<String> tagNames, String contents, Long categoryId) {
QBoard board = QBoard.board;
QTagBoard tagBoard = QTagBoard.tagBoard;
QTag tag = QTag.tag;
BooleanBuilder builder = new BooleanBuilder();
// 카테고리 조건
if (categoryId != null) {
builder.and(board.category.id.eq(categoryId)); //카테고리 ID와 같은 ID값만 추출
}
// 태그 조건 : 각 태그를 모두(AND)를 포함한 게시글
// select board_id from tag_board
//where tag_id in(select id from tag where name in("a","b"))
//GROUP BY board_id HAVING COUNT(tag_id) = {입력받은 태그 사이즈}; -> 태그 개수 확인
// 태그이름 리스트 -> ID변환
if (tagNames != null && !tagNames.isEmpty()) {
// 태그 이름을 기반으로 태그 ID 조회
List<Long> tagIds = queryFactory
.select(tag.id)
.from(tag)
.where(tag.name.in(tagNames))
.fetch();
// 태그가 모두 포함된 게시글 필터링
builder.and(board.id.in(
queryFactory
.select(tagBoard.board.id)
.from(tagBoard)
.where(tagBoard.tag.id.in(tagIds))
.groupBy(tagBoard.board.id)
.having(tagBoard.tag.id.count().eq((long) tagNames.size()))
.fetch()
));
}
// 검색어(게시글 내용) 조건 : 해당 내용이 포함된 게시글(대소문자 구분X)
// select board_id from board
// where Lower(board.content) like concat('%',LOWER(:contents,'%')
if (contents != null && !contents.isEmpty()) {
builder.and(board.content.containsIgnoreCase(contents)); // = Like %LOWER{contents}%
}
return builder;
}
// 빌더 적용 패치함수
private PageImpl<BoardResponseDto> fetchBoards(Pageable pageable, BooleanBuilder builder) {
QBoard board = QBoard.board;
QTagBoard tagBoard = QTagBoard.tagBoard;
List<Board> boards = queryFactory
.selectDistinct(board)
.from(board)
.leftJoin(board.tagBoards, tagBoard)
.where(builder)
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
long total = queryFactory
.selectDistinct(board)
.from(board)
.leftJoin(board.tagBoards, tagBoard)
.where(builder)
.fetchCount();
List<BoardResponseDto> content = boards.stream()
.map(BoardResponseDto::fromEntity)
.collect(Collectors.toList());
return new PageImpl<>(content, pageable, total);
}
🎯 리팩토링 목표
[검색성능 최적화]
검색 성능을 높인다. (조회 로직 속도 향상, 필요없는 쿼리 요청 삭제, 검색 필터링 고도화)
[Hateoas 적용]
Hateoassms 서버가 클라이언트에게 하이퍼미디어(링크를 통해 공유된 자원)를 통해 정보를 동적으로 제공해주는 방법이다.
PAGEMODE
Pageable 자료구조의 응답 표현을 dto에 바인딩하기 위해 필요한 객체를 이고
내부에서 페이지의총 갯수를 반환함
long total = countQuery
.where(builder)
.fetchCount();
해당 기능은 기존 코드와 성능 차이는 작은서비스에선 크게나지 않음 -> 차라리 HATEAOS의 장점을 가져가고 이를 통해 REST 규칙을 지키며 개발하기!
🛠 작업 내용
📎 참고 자료
https://www.youtube.com/watch?v=RP_f5dMoHFc (PageModel 부분 참고) -- 그런 REST API로 괜찮은가?
https://docs.spring.io/spring-hateoas/docs/current/api/org/springframework/hateoas/PagedModel.html - PagedModel (Spring HATEOAS 1.3.3 API)
https://esbook.kimjmin.net/ - Elastic Search
🔄 리팩토링 대상
[검색 도메인]
: Board.sevice/ getallBoards, getBoardByCategory
🎯 리팩토링 목표
[검색성능 최적화]
검색 성능을 높인다. (조회 로직 속도 향상, 필요없는 쿼리 요청 삭제, 검색 필터링 고도화)
[Hateoas 적용]
Hateoassms 서버가 클라이언트에게 하이퍼미디어(링크를 통해 공유된 자원)를 통해 정보를 동적으로 제공해주는 방법이다.
PAGEMODE
Pageable 자료구조의 응답 표현을 dto에 바인딩하기 위해 필요한 객체를 이고
내부에서 페이지의총 갯수를 반환함
해당 기능은 기존 코드와 성능 차이는 작은서비스에선 크게나지 않음 -> 차라리 HATEAOS의 장점을 가져가고 이를 통해 REST 규칙을 지키며 개발하기!
🛠 작업 내용
📎 참고 자료
https://www.youtube.com/watch?v=RP_f5dMoHFc (PageModel 부분 참고) -- 그런 REST API로 괜찮은가?
https://docs.spring.io/spring-hateoas/docs/current/api/org/springframework/hateoas/PagedModel.html - PagedModel (Spring HATEOAS 1.3.3 API)
https://esbook.kimjmin.net/ - Elastic Search