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

[BE] refactor: 상품 랭킹 알고리즘 개선 #756

Merged
merged 6 commits into from
Oct 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -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);
Go-Jaecheol marked this conversation as resolved.
Show resolved Hide resolved
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));
Go-Jaecheol marked this conversation as resolved.
Show resolved Hide resolved
복수_리뷰_저장(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