Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

카페 검색 기능 개발 #443

Merged
merged 19 commits into from
Sep 26, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ public CafeController(final CafeService cafeService) {
}

@GetMapping
public ResponseEntity<List<CafeResponse>> getCafesForLoggedInMember(final Member member) {
final List<CafeResponse> cafeResponses = cafeService.getCafesForLoginMember(member, PAGE_SIZE);
public ResponseEntity<List<CafeResponse>> getCafesForLoggedInMember(@LoginUser final String memberId) {
List<CafeResponse> cafeResponses = cafeService.getCafesForLoginMember(memberId, PAGE_SIZE);
return ResponseEntity.ok(cafeResponses);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.project.yozmcafe.controller.dto.cafe.LikedCafeResponse;
import com.project.yozmcafe.controller.dto.cafe.CafeThumbnailResponse;
import com.project.yozmcafe.domain.member.Member;
import com.project.yozmcafe.service.LikedCafeService;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@

import static com.project.yozmcafe.domain.cafe.QCafe.cafe;
import static com.project.yozmcafe.domain.menu.QMenu.menu;
import static com.querydsl.core.types.dsl.Expressions.numberTemplate;
import static io.micrometer.common.util.StringUtils.isBlank;

@Repository
public class CafeCustomRepositoryImpl extends QuerydslRepositorySupport implements CafeCustomRepository {

private static final double MATCH_THRESHOLD = 0.0;

public CafeCustomRepositoryImpl() {
super(Cafe.class);
}
Expand All @@ -22,8 +25,8 @@ public List<Cafe> findAllBy(final String cafeNameWord, final String menuWord, fi
return from(cafe)
.innerJoin(menu).on(menu.cafe.eq(cafe))
.where(
contains(menu.name, menuWord),
contains(cafe.name, cafeNameWord),
contains(menu.name, menuWord),
contains(cafe.address, addressWord))
.fetch();
}
Expand All @@ -36,11 +39,14 @@ public List<Cafe> findAllBy(final String cafeNameWord, final String addressWord)
.fetch();
}

private BooleanExpression contains(final StringPath target, final String string) {
if (isBlank(string)) {
private BooleanExpression contains(final StringPath target, final String searchWord) {
if (isBlank(searchWord)) {
return null;
}

return target.containsIgnoreCase(string);
final String formattedSearchWord = "\"" + searchWord + "\"";
return numberTemplate(Double.class, "function('match_against', {0}, {1})",
target, formattedSearchWord)
.gt(MATCH_THRESHOLD);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.project.yozmcafe.domain.cafe;

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

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

public class CustomFunctionContributor implements FunctionContributor {

private static final String FUNCTION_NAME = "match_against";
private static final String FUNCTION_PATTERN = "match (?1) against (?2 in boolean mode)";

Comment on lines +8 to +12
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RepositoryImpl에서 match_against라는 것을 봤을 때 이게 뭐지?? 싶었는데 패턴 매칭으로 여기서 함수를 정의하고 있었군요.

match against 문을 바로 쓰지 않고 함수화하는 이유가 궁금합니다.
어떤 이점이 있나요??

Copy link
Collaborator Author

@hum02 hum02 Sep 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 가능하면 특화구문을 최소한의 의존성으로 사용하고 싶어요!

 private BooleanExpression contains(final StringPath target, final String searchWord) {
        if (isBlank(searchWord)) {
            return null;
        }
        return booleanTemplate("match({0}) against ({1} in boolean mode) > 0", target, searchWord);
    }

이런 식으로 match against문을 바로 쓰는 것을 생각하신 게 맞나요?
이렇게 사용할 시 hql이 이런 특화 구문을 지원해주지 않아 hibernate에서 parsing할 때 exception이 발생합니다 ㅜ.
image

그렇다고 native query사용을 위해 entityManager를 직접 사용하면 querydsl을 통한 동적쿼리의 의미가 없어지는 것 같고....
때문에 함수 등록을 하는 방법을 택했습니다! 다른 방법이 있을까요?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

query dsl은 말 그대로 DSL로 편하게 동적 쿼리를 작성하기 위함이고 native query를 사용하는 것은 피할 수 없다고 생각해요.
필요하면 JDBC Template을 쓰거나, Entity Manager로 날리거나 하는 것이 당연하다고 생각합니다!

근데 만약 여기서 Entity Manager를 사용하면 좀 더 추상객체(Entity Manager)의 의존만으로 처리할 수 있지 않나 해서 남겼어요!
어떤 장점 때문에 했는지 궁금해서요.

native query가 필요할 때마다 native query가 아닌 Query DSL로 하실 것인가요??

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아 Entity Manager로 변경하라는 뜻은 아닙니다!
지금 그대로도 좋아요!! 단순 궁금증입니다.

Copy link
Collaborator Author

@hum02 hum02 Sep 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

querydsl의 where에 native쿼리가 들어가야 처음 querydsl을 쓸 때 의도했던 대로
하나의 쿼리 template으로 동적인 쿼리가 가능하다 생각해요!

Entity Manager를 쓰면서 이를 querydsl에 적용하려면 EntityManager의 쿼리 형식을 booleanExpression으로 바꿔야 하는 데 그게 가능한지 모르겠네요...

@Override
public void contributeFunctions(final FunctionContributions functionContributions) {
functionContributions.getFunctionRegistry()
.registerPattern(FUNCTION_NAME, FUNCTION_PATTERN,
functionContributions.getTypeConfiguration().getBasicTypeRegistry().resolve(DOUBLE));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ public class CafeService {
private final UnViewedCafeService unViewedCafeService;
private final CafeRankGenerator cafeRankGenerator;

public CafeService(final CafeRepository cafeRepository, final UnViewedCafeService unViewedCafeService,
final CafeRankGenerator cafeRankGenerator) {
public CafeService(final CafeRepository cafeRepository, final MemberService memberService,
final UnViewedCafeService unViewedCafeService, final CafeRankGenerator cafeRankGenerator) {
this.cafeRepository = cafeRepository;
this.memberService = memberService;
this.unViewedCafeService = unViewedCafeService;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
com.project.yozmcafe.domain.cafe.CustomFunctionContributor
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

함수를 등록하려면 이 부분이 필요한 건가요??
어떤 부분인지 궁금해요

Copy link
Collaborator Author

@hum02 hum02 Sep 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

여기서 fuctionContirbutor를 사용하려면 sericeLoader에서 스캔하도록 META-INF경로에 파일을 만들거나
코드를 통해 등록하려면 applyFunctions등을 이용하라 안내하는데요.
첫번째 방법을 위해 serviceLoader가 스캔하는 경로에 파일을 등록했습니다.

두번 째 방법인
image
이 방식으로 해보니 여전히 직접 설정을 집어넣어야 하는 게 존재해서 이러느니 META-INF에 파일을 만드는 지금 방식이 더 낫다고 생각합니다

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ALTER TABLE cafe ADD FULLTEXT INDEX cafe_name_idx (name) WITH PARSER NGRAM;

ALTER TABLE cafe ADD FULLTEXT INDEX address_idx (address) WITH PARSER NGRAM;

ALTER TABLE menu ADD FULLTEXT INDEX menu_name_idx (name) WITH PARSER NGRAM;
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ void getCafesBySearchWhenNotSearchMenu() {
//given, when
final Response response = given().log().all()
.when()
.get("/cafes/search?cafeName=n2&address=2");
.get("/cafes/search?cafeName=n2&address=addr");

//then
final List<CafeSearchResponse> cafeSearchResponses = getCafeSearchResponses(response);
Expand Down