Skip to content

Commit

Permalink
[BE] refactor: 상품 랭킹 알고리즘 개선 (#756)
Browse files Browse the repository at this point in the history
* refactor: 상품 랭킹 조회 시 기간 설정

* test: 상품 랭킹 관련 Repository 테스트 추가 및 수정

* test: 상품 랭킹 관련 서비스 테스트 수정

* style: import 정렬 순서 변경

* fix: 충돌 해결
  • Loading branch information
Go-Jaecheol authored Oct 18, 2023
1 parent 9342c22 commit 87c5ac8
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import com.funeat.review.persistence.ReviewRepository;
import com.funeat.review.persistence.ReviewTagRepository;
import com.funeat.tag.domain.Tag;
import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -119,7 +120,9 @@ public ProductResponse findProductDetail(final Long productId) {
}

public RankingProductsResponse getTop3Products() {
final List<ProductReviewCountDto> productsAndReviewCounts = productRepository.findAllByAverageRatingGreaterThan3();
final LocalDateTime endDateTime = LocalDateTime.now();
final LocalDateTime startDateTime = endDateTime.minusWeeks(2L);
final List<ProductReviewCountDto> productsAndReviewCounts = productRepository.findAllByAverageRatingGreaterThan3(startDateTime, endDateTime);
final Comparator<ProductReviewCountDto> rankingScoreComparator = Comparator.comparing(
(ProductReviewCountDto it) -> it.getProduct().calculateRankingScore(it.getReviewCount())
).reversed();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.funeat.common.repository.BaseRepository;
import com.funeat.product.domain.Product;
import com.funeat.product.dto.ProductReviewCountDto;
import java.time.LocalDateTime;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
Expand All @@ -15,8 +16,10 @@ public interface ProductRepository extends BaseRepository<Product, Long> {
+ "FROM Product p "
+ "LEFT JOIN Review r ON r.product.id = p.id "
+ "WHERE p.averageRating > 3.0 "
+ "AND r.createdAt BETWEEN :startDateTime AND :endDateTime "
+ "GROUP BY p.id")
List<ProductReviewCountDto> findAllByAverageRatingGreaterThan3();
List<ProductReviewCountDto> findAllByAverageRatingGreaterThan3(final LocalDateTime startDateTime,
final LocalDateTime endDateTime);

@Query("SELECT p FROM Product p "
+ "WHERE p.name LIKE CONCAT('%', :name, '%') "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,16 +109,16 @@ class 상품_개수에_대한_테스트 {
final var review1_4 = 리뷰_이미지test3_평점3점_재구매O_생성(member1, product1, 0L);
final var review2_1 = 리뷰_이미지test4_평점4점_재구매O_생성(member1, product2, 0L);
final var review2_2 = 리뷰_이미지test4_평점4점_재구매O_생성(member1, product2, 0L);
final var review3_1 = 리뷰_이미지test5_평점5점_재구매X_생성(member1, product2, 0L);
final var review4_1 = 리뷰_이미지test4_평점4점_재구매X_생성(member1, product2, 0L);
final var review4_2 = 리뷰_이미지test3_평점3점_재구매X_생성(member1, product2, 0L);
final var review4_3 = 리뷰_이미지test5_평점5점_재구매X_생성(member1, product2, 0L);
final var review3_1 = 리뷰_이미지test5_평점5점_재구매X_생성(member1, product3, 0L);
final var review4_1 = 리뷰_이미지test4_평점4점_재구매X_생성(member1, product4, 0L);
final var review4_2 = 리뷰_이미지test3_평점3점_재구매X_생성(member1, product4, 0L);
final var review4_3 = 리뷰_이미지test5_평점5점_재구매X_생성(member1, product4, 0L);
복수_리뷰_저장(review1_1, review1_2, review1_3, review1_4, review2_1, review2_2, review3_1, review4_1,
review4_2, review4_3);

final var rankingProductDto1 = RankingProductDto.toDto(product2);
final var rankingProductDto2 = RankingProductDto.toDto(product3);
final var rankingProductDto3 = RankingProductDto.toDto(product4);
final var rankingProductDto1 = RankingProductDto.toDto(product3);
final var rankingProductDto2 = RankingProductDto.toDto(product4);
final var rankingProductDto3 = RankingProductDto.toDto(product2);
final var rankingProductDtos = List.of(rankingProductDto1, rankingProductDto2, rankingProductDto3);
final var expected = RankingProductsResponse.toResponse(rankingProductDtos);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,23 @@
import static com.funeat.fixture.MemberFixture.멤버_멤버1_생성;
import static com.funeat.fixture.MemberFixture.멤버_멤버2_생성;
import static com.funeat.fixture.MemberFixture.멤버_멤버3_생성;
import static com.funeat.fixture.PageFixture.가격_내림차순;
import static com.funeat.fixture.PageFixture.가격_오름차순;
import static com.funeat.fixture.PageFixture.리뷰수_내림차순;
import static com.funeat.fixture.PageFixture.페이지요청_기본_생성;
import static com.funeat.fixture.PageFixture.페이지요청_생성;
import static com.funeat.fixture.PageFixture.평균_평점_내림차순;
import static com.funeat.fixture.PageFixture.평균_평점_오름차순;
import static com.funeat.fixture.ProductFixture.상품_망고빙수_가격5000원_평점4점_생성;
import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격1000원_리뷰3개_생성;
import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격1000원_평점1점_생성;
import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격1000원_평점2점_생성;
import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격1000원_평점3점_생성;
import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격1000원_평점4점_생성;
import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격1000원_평점5점_생성;
import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격2000원_리뷰1개_생성;
import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격2000원_평점1점_생성;
import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격2000원_평점4점_생성;
import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격3000원_리뷰5개_생성;
import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격3000원_평점1점_생성;
import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격3000원_평점5점_생성;
import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격4000원_평점1점_생성;
import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격4000원_평점2점_생성;
import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격5000원_리뷰0개_생성;
import static com.funeat.fixture.ProductFixture.상품_삼각김밥_가격5000원_평점1점_생성;
import static com.funeat.fixture.ProductFixture.상품_애플망고_가격3000원_평점5점_생성;
import static com.funeat.fixture.ReviewFixture.리뷰_이미지test1_평점1점_재구매X_생성;
import static com.funeat.fixture.ReviewFixture.리뷰_이미지test3_평점3점_재구매O_생성;
import static com.funeat.fixture.ReviewFixture.리뷰_이미지test4_평점4점_재구매X_생성;
import static com.funeat.fixture.ReviewFixture.리뷰_이미지test5_평점5점_재구매O_생성;
import static com.funeat.fixture.ReviewFixture.리뷰_이미지test5_평점5점_재구매X_생성;
import static org.assertj.core.api.Assertions.assertThat;

import com.funeat.common.RepositoryTest;
import com.funeat.product.dto.ProductInCategoryDto;
import com.funeat.product.dto.ProductReviewCountDto;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -65,20 +48,52 @@ class findAllByAverageRatingGreaterThan3_성공_테스트 {
final var member3 = 멤버_멤버3_생성();
복수_멤버_저장(member1, member2, member3);

final var review1_1 = 리뷰_이미지test1_평점1점_재구매X_생성(member1, product1, 0L);
final var review1_2 = 리뷰_이미지test5_평점5점_재구매O_생성(member2, product1, 0L);
final var review2_1 = 리뷰_이미지test3_평점3점_재구매O_생성(member3, product2, 0L);
final var review2_2 = 리뷰_이미지test4_평점4점_재구매X_생성(member1, product2, 0L);
final var review2_3 = 리뷰_이미지test5_평점5점_재구매O_생성(member2, product2, 0L);
final var review3_1 = 리뷰_이미지test5_평점5점_재구매O_생성(member1, product3, 0L);
final var review1_1 = 리뷰_이미지test5_평점5점_재구매X_생성(member1, product1, 0L, LocalDateTime.now().minusDays(2L));
final var review1_2 = 리뷰_이미지test5_평점5점_재구매X_생성(member2, product1, 0L, LocalDateTime.now().minusDays(3L));
final var review2_1 = 리뷰_이미지test5_평점5점_재구매X_생성(member3, product2, 0L, LocalDateTime.now().minusDays(10L));
final var review2_2 = 리뷰_이미지test5_평점5점_재구매X_생성(member1, product2, 0L, LocalDateTime.now().minusDays(1L));
final var review2_3 = 리뷰_이미지test5_평점5점_재구매X_생성(member2, product2, 0L, LocalDateTime.now().minusDays(9L));
final var review3_1 = 리뷰_이미지test5_평점5점_재구매X_생성(member1, product3, 0L, LocalDateTime.now().minusDays(8L));
복수_리뷰_저장(review1_1, review1_2, review2_1, review2_2, review2_3, review3_1);

final var productReviewCountDto1 = new ProductReviewCountDto(product2, 3L);
final var productReviewCountDto2 = new ProductReviewCountDto(product3, 1L);
final var expected = List.of(productReviewCountDto1, productReviewCountDto2);

// when
final var actual = productRepository.findAllByAverageRatingGreaterThan3();
final var startDateTime = LocalDateTime.now().minusWeeks(2L);
final var endDateTime = LocalDateTime.now();
final var actual = productRepository.findAllByAverageRatingGreaterThan3(startDateTime, endDateTime);

// then
assertThat(actual).usingRecursiveComparison()
.isEqualTo(expected);
}

@Test
void 기간_안에_리뷰가_존재하는_상품이_없으면_빈_리스트를_반환한다() {
// given
final var category = 카테고리_간편식사_생성();
단일_카테고리_저장(category);

final var product1 = 상품_삼각김밥_가격1000원_평점3점_생성(category);
final var product2 = 상품_삼각김밥_가격2000원_평점4점_생성(category);
복수_상품_저장(product1, product2);

final var member1 = 멤버_멤버1_생성();
final var member2 = 멤버_멤버2_생성();
복수_멤버_저장(member1, member2);

final var review1 = 리뷰_이미지test5_평점5점_재구매X_생성(member1, product1, 0L, LocalDateTime.now().minusDays(15L));
final var review2 = 리뷰_이미지test5_평점5점_재구매X_생성(member2, product2, 0L, LocalDateTime.now().minusWeeks(3L));
복수_리뷰_저장(review1, review2);

final var expected = Collections.emptyList();

// when
final var startDateTime = LocalDateTime.now().minusWeeks(2L);
final var endDateTime = LocalDateTime.now();
final var actual = productRepository.findAllByAverageRatingGreaterThan3(startDateTime, endDateTime);

// then
assertThat(actual).usingRecursiveComparison()
Expand Down

0 comments on commit 87c5ac8

Please sign in to comment.