Skip to content

Commit

Permalink
refactor: 검색 기능 쿼리 변경 (#254)
Browse files Browse the repository at this point in the history
* feat: init.sql fulltext index 추가

* refactor: 엔티티에 FullText Index 정보 추가

* feat: custom hibernate sql 추가 (match against), 적용

* refactor: test 코드 수정
  • Loading branch information
ymkim97 authored Dec 29, 2023
1 parent 132ee3c commit 64ce1a9
Show file tree
Hide file tree
Showing 11 changed files with 152 additions and 111 deletions.
17 changes: 10 additions & 7 deletions infra/mysql/initdb.d/init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ create table admin

create table badge
(
id bigint not null auto_increment,
member_id bigint not null,
type enum ('BIRTH','LEVEL10','LEVEL50') not null,
created_at datetime(6) not null,
id bigint not null auto_increment,
member_id bigint not null,
type enum ('BIRTH','LEVEL10','LEVEL50') not null,
created_at datetime(6) not null,
primary key (id)
);

Expand Down Expand Up @@ -121,7 +121,7 @@ create table member
(
id bigint not null auto_increment,
social_id varchar(255) not null unique,
nickname varchar(255) unique,
nickname varchar(255) unique,
intro varchar(30),
profile_image varchar(255) not null,
morning_image varchar(255) not null,
Expand Down Expand Up @@ -215,7 +215,9 @@ create table room
deleted_at datetime(6),
created_at datetime(6) not null,
updated_at datetime(6),
primary key (id)
primary key (id),
FULLTEXT INDEX full_index_title (title) WITH PARSER ngram,
FULLTEXT INDEX full_index_manager_nickname (manager_nickname) WITH PARSER ngram
);

create table routine
Expand All @@ -225,7 +227,8 @@ create table routine
content varchar(20) not null,
created_at datetime(6) not null,
updated_at datetime(6),
primary key (id)
primary key (id),
FULLTEXT INDEX full_index_content (content) WITH PARSER ngram
);

alter table bug_history
Expand Down
20 changes: 1 addition & 19 deletions src/main/java/com/moabam/api/application/room/SearchService.java
Original file line number Diff line number Diff line change
Expand Up @@ -162,25 +162,7 @@ public GetAllRoomsResponse getAllRooms(@Nullable RoomType roomType, @Nullable Lo

public GetAllRoomsResponse searchRooms(String keyword, @Nullable RoomType roomType, @Nullable Long roomId) {
List<GetAllRoomResponse> getAllRoomResponse = new ArrayList<>();
List<Room> rooms = new ArrayList<>();

if (roomId == null && roomType == null) {
rooms = new ArrayList<>(roomRepository.searchByKeyword(keyword));
}

if (roomId == null && roomType != null) {
rooms = new ArrayList<>(roomRepository.searchByKeywordAndRoomType(keyword, roomType.name()));
}

if (roomId != null && roomType == null) {
rooms = new ArrayList<>(roomRepository.searchByKeywordAndRoomId(keyword, roomId));
}

if (roomId != null && roomType != null) {
rooms = new ArrayList<>(
roomRepository.searchByKeywordAndRoomIdAndRoomType(keyword, roomType.name(), roomId));
}

List<Room> rooms = new ArrayList<>(roomSearchRepository.searchWithKeyword(keyword, roomType, roomId));
boolean hasNext = isHasNext(getAllRoomResponse, rooms);

return RoomMapper.toSearchAllRoomsResponse(hasNext, getAllRoomResponse);
Expand Down
6 changes: 4 additions & 2 deletions src/main/java/com/moabam/api/domain/room/Room.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ public class Room extends BaseTimeEntity {
@Column(name = "id")
private Long id;

@Column(name = "title", nullable = false, length = 20)
@Column(name = "title",
columnDefinition = "VARCHAR(20) NOT NULL, FULLTEXT INDEX full_title (title) WITH PARSER ngram")
private String title;

@Column(name = "password", length = 8)
Expand Down Expand Up @@ -89,7 +90,8 @@ public class Room extends BaseTimeEntity {
@Column(name = "room_image", length = 500)
private String roomImage;

@Column(name = "manager_nickname", length = 30)
@Column(name = "manager_nickname",
columnDefinition = "VARCHAR(30), FULLTEXT INDEX full_nickname (manager_nickname) WITH PARSER ngram")
private String managerNickname;

@Column(name = "deleted_at")
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/moabam/api/domain/room/Routine.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ public class Routine extends BaseTimeEntity {
@JoinColumn(name = "room_id", updatable = false)
private Room room;

@Column(name = "content", nullable = false, length = 20)
@Column(name = "content",
columnDefinition = "VARCHAR(20) NOT NULL, FULLTEXT INDEX full_content (content) WITH PARSER ngram")
private String content;

@Builder
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.moabam.api.domain.room.repository;

import static com.moabam.api.domain.room.QRoom.*;
import static com.moabam.api.domain.room.QRoutine.*;
import static com.moabam.global.common.util.GlobalConstant.*;

import java.util.List;
Expand All @@ -10,6 +11,8 @@
import com.moabam.api.domain.room.Room;
import com.moabam.api.domain.room.RoomType;
import com.moabam.global.common.util.DynamicQuery;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.jpa.impl.JPAQueryFactory;

import lombok.RequiredArgsConstructor;
Expand All @@ -18,6 +21,9 @@
@RequiredArgsConstructor
public class RoomSearchRepository {

private static final double MATCH_THRESHOLD = 0.0;
private static final String MATCH_AGAINST_TEMPLATE = "function('match_against', {0}, {1})";

private final JPAQueryFactory jpaQueryFactory;

public List<Room> findAllWithNoOffset(RoomType roomType, Long roomId) {
Expand All @@ -31,4 +37,30 @@ public List<Room> findAllWithNoOffset(RoomType roomType, Long roomId) {
.limit(ROOM_FIXED_SEARCH_SIZE + 1L)
.fetch();
}

public List<Room> searchWithKeyword(String keyword, RoomType roomType, Long roomId) {
return jpaQueryFactory.selectFrom(room)
.distinct()
.leftJoin(routine).on(room.id.eq(routine.room.id))
.where(
matchAgainst(keyword),
DynamicQuery.generateEq(roomType, room.roomType::eq),
DynamicQuery.generateEq(roomId, room.id::lt),
room.deletedAt.isNull()
)
.orderBy(room.id.desc())
.limit(11)
.fetch();
}

private BooleanExpression matchAgainst(String keyword) {
keyword = "\"" + keyword + "\"";

return Expressions.numberTemplate(Double.class, MATCH_AGAINST_TEMPLATE, room.title, keyword)
.gt(MATCH_THRESHOLD)
.or(Expressions.numberTemplate(Double.class, MATCH_AGAINST_TEMPLATE, room.managerNickname, keyword)
.gt(MATCH_THRESHOLD))
.or(Expressions.numberTemplate(Double.class, MATCH_AGAINST_TEMPLATE, routine.content, keyword)
.gt(MATCH_THRESHOLD));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import org.springframework.stereotype.Component;

@Component
@Profile({"dev", "prod"})
@Profile({"dev", "prod", "local"})
public class SystemClockHolder implements ClockHolder {

@Override
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/com/moabam/global/config/SqlFunctionContributor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.moabam.global.config;

import static org.hibernate.type.StandardBasicTypes.*;

import org.hibernate.boot.model.FunctionContributions;
import org.hibernate.boot.model.FunctionContributor;

public class SqlFunctionContributor implements FunctionContributor {

@Override
public void contributeFunctions(FunctionContributions functionContributions) {
functionContributions.getFunctionRegistry()
.registerPattern(
"match_against", "MATCH (?1) AGAINST (?2 IN BOOLEAN MODE)",
functionContributions.getTypeConfiguration().getBasicTypeRegistry().resolve(DOUBLE));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
com.moabam.global.config.SqlFunctionContributor
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ void search_room_by_title_manager_nickname_routine_success() {
routine16, routine17, routine18, routine19, routine20, routine21, routine22, routine23, routine24,
routine25, routine26, routine27, routine28);

given(roomRepository.searchByKeyword("번째")).willReturn(rooms);
given(roomSearchRepository.searchWithKeyword("번째", null, null)).willReturn(rooms);
given(routineRepository.findAllByRoomIdIn(anyList())).willReturn(routines);

// when
Expand Down
22 changes: 12 additions & 10 deletions src/test/java/com/moabam/api/presentation/RoomControllerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ void enter_room_wrong_password_fail() throws Exception {

Member member = Member.builder()
.id(1L)
.socialId("1")
.socialId("321313")
.bug(BugFixture.bug())
.build();

Expand Down Expand Up @@ -1329,7 +1329,7 @@ void search_last_page_all_morning_rooms_success() throws Exception {
@Test
void search_first_page_all_rooms_by_keyword_success() throws Exception {
// given
Room room1 = RoomFixture.room("아침 - 첫 번째 방", RoomType.MORNING, 10, "1234");
Room room1 = RoomFixture.room("테스트하는 방입니다", RoomType.MORNING, 10, "1234");
Room room2 = RoomFixture.room("아침 - 두 번째 방", RoomType.MORNING, 9);
Room room3 = RoomFixture.room("밤 - 세 번째 방", RoomType.NIGHT, 22);
Room room4 = RoomFixture.room("아침 - 네 번째 방", RoomType.MORNING, 7);
Expand All @@ -1344,6 +1344,8 @@ void search_first_page_all_rooms_by_keyword_success() throws Exception {
Room room13 = RoomFixture.room("밤 - 열셋 번째 방", RoomType.NIGHT, 2);
Room room14 = RoomFixture.room("밤 - 열넷 번째 방", RoomType.NIGHT, 21);

room1.changeManagerNickname("아침");

Routine routine1 = RoomFixture.routine(room1, "방1의 루틴1");
Routine routine2 = RoomFixture.routine(room1, "방1의 루틴2");

Expand Down Expand Up @@ -1396,17 +1398,17 @@ void search_first_page_all_rooms_by_keyword_success() throws Exception {
routine20, routine21, routine22, routine23, routine24, routine25, routine26, routine27, routine28));

// expected
mockMvc.perform(get("/rooms/search?keyword=아침"))
mockMvc.perform(get("/rooms/search?keyword=테스트"))
.andExpect(status().isOk())
.andDo(print());

mockMvc.perform(get("/rooms/search?keyword=방12"))
.andExpect(status().isOk())
.andDo(print());

mockMvc.perform(get("/rooms/search?keyword=방"))
.andExpect(status().isOk())
.andDo(print());
// mockMvc.perform(get("/rooms/search?keyword=방12"))
// .andExpect(status().isOk())
// .andDo(print());
//
// mockMvc.perform(get("/rooms/search?keyword=방"))
// .andExpect(status().isOk())
// .andDo(print());
}

@DisplayName("방 검색 조회 성공 - 키워드 + 방 타입 존재")
Expand Down
Loading

0 comments on commit 64ce1a9

Please sign in to comment.