Skip to content
Open
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 @@ -3,9 +3,7 @@
import com.loopers.application.product.ProductInfo;
import com.loopers.domain.product.Product;
import com.loopers.domain.product.ProductService;
import com.loopers.domain.ranking.Ranking;
import com.loopers.domain.ranking.RankingService;
import com.loopers.domain.ranking.RankingType;
import com.loopers.domain.ranking.*;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -20,14 +18,27 @@
public class RankingFacade {

private final RankingService rankingService;
private final PeriodRankingService periodRankingService;
private final ProductService productService;

/**
* TOP N ๋žญํ‚น ์กฐํšŒ (์ƒํ’ˆ ์ •๋ณด ํฌํ•จ)
*/
@Transactional(readOnly = true)
public List<RankingInfo> getTopRanking(RankingType rankingType, LocalDate date, int limit) {
List<Ranking> entries = rankingService.getTopRanking(rankingType, date, limit);
public List<RankingInfo> getTopRanking(
RankingType rankingType,
PeriodType periodType,
LocalDate date,
int limit
) {
// period๊ฐ€ null์ด๋ฉด DAILY๋กœ ์ฒ˜๋ฆฌ
PeriodType period = periodType != null ? periodType : PeriodType.DAILY;

List<Ranking> entries = switch (period) {
case DAILY -> rankingService.getTopRanking(rankingType, LocalDate.now(), limit);
case WEEKLY -> periodRankingService.getTopWeeklyRanking(rankingType, date, limit);
case MONTHLY -> periodRankingService.getTopMonthlyRanking(rankingType, date, limit);
};

if (entries.isEmpty()) {
return List.of();
Expand All @@ -40,9 +51,21 @@ public List<RankingInfo> getTopRanking(RankingType rankingType, LocalDate date,
* ํŽ˜์ด์ง€๋„ค์ด์…˜ ๋žญํ‚น ์กฐํšŒ
*/
@Transactional(readOnly = true)
public List<RankingInfo> getRankingWithPaging(RankingType rankingType, LocalDate date,
int page, int size) {
List<Ranking> entries = rankingService.getRankingWithPaging(rankingType, date, page, size);
public List<RankingInfo> getRankingWithPaging(
RankingType rankingType,
PeriodType periodType,
LocalDate date,
int page,
int size
) {

PeriodType period = periodType != null ? periodType : PeriodType.DAILY;

List<Ranking> entries = switch (period) {
case DAILY -> rankingService.getRankingWithPaging(rankingType, LocalDate.now(), page, size);
case WEEKLY -> periodRankingService.getWeeklyRankingWithPaging(rankingType, date, page, size);
case MONTHLY -> periodRankingService.getMonthlyRankingWithPaging(rankingType, date, page, size);
};

if (entries.isEmpty()) {
return List.of();
Expand All @@ -55,7 +78,11 @@ public List<RankingInfo> getRankingWithPaging(RankingType rankingType, LocalDate
* ํŠน์ • ์ƒํ’ˆ์˜ ํŠน์ • ๋žญํ‚น ์กฐํšŒ
*/
@Transactional(readOnly = true)
public RankingInfo getProductRanking(RankingType rankingType, LocalDate date, Long productId) {
public RankingInfo getProductRanking(
RankingType rankingType,
LocalDate date,
Long productId
) {
Ranking entry = rankingService.getProductRanking(rankingType, date, productId);

if (entry == null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.loopers.domain.metrics;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.Immutable;

import java.time.LocalDate;
import java.time.ZonedDateTime;

/**
* ์›”๊ฐ„ ์ƒํ’ˆ ์ง‘๊ณ„ Materialized View (์ฝ๊ธฐ ์ „์šฉ)
* commerce-collector์—์„œ ์ƒ์„ฑํ•œ ์ง‘๊ณ„ ๋ฐ์ดํ„ฐ ์กฐํšŒ์šฉ
*/
@Entity
@Table(name = "mv_product_metrics_monthly")
@Getter
@NoArgsConstructor
@Immutable // ์ฝ๊ธฐ ์ „์šฉ
public class ProductMetricsMonthly {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "product_id", nullable = false)
private Long productId;

@Column(name = "year", nullable = false)
private Integer year;

@Column(name = "month", nullable = false)
private Integer month;

@Column(name = "period_start_date", nullable = false)
private LocalDate periodStartDate;

@Column(name = "period_end_date", nullable = false)
private LocalDate periodEndDate;

@Column(name = "total_like_count", nullable = false)
private Long totalLikeCount;

@Column(name = "total_view_count", nullable = false)
private Long totalViewCount;

@Column(name = "total_order_count", nullable = false)
private Long totalOrderCount;

@Column(name = "aggregated_at")
private ZonedDateTime aggregatedAt;

@Column(name = "created_at")
private ZonedDateTime createdAt;

@Column(name = "updated_at")
private ZonedDateTime updatedAt;

/**
* ์ข…ํ•ฉ ์ ์ˆ˜ ๊ณ„์‚ฐ (๊ฐ€์ค‘์น˜ ์ ์šฉ)
* Score = (like * 0.2) + (view * 0.1) + (order * 0.6)
*/
public double calculateCompositeScore() {
return (totalLikeCount * 0.2) + (totalViewCount * 0.1) + (totalOrderCount * 0.6);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.loopers.domain.metrics;

import java.util.List;
import java.util.Optional;

public interface ProductMetricsMonthlyRepository {
/**
* ํŠน์ • ๋…„๋„/์›”์˜ ๋žญํ‚น ์กฐํšŒ (์ข‹์•„์š” ๊ธฐ์ค€ ์ •๋ ฌ)
*/
List<ProductMetricsMonthly> findByYearAndMonthOrderByLikeCountDesc(int year, int month, int limit);

/**
* ํŠน์ • ๋…„๋„/์›”์˜ ๋žญํ‚น ์กฐํšŒ (์กฐํšŒ์ˆ˜ ๊ธฐ์ค€ ์ •๋ ฌ)
*/
List<ProductMetricsMonthly> findByYearAndMonthOrderByViewCountDesc(int year, int month, int limit);

/**
* ํŠน์ • ๋…„๋„/์›”์˜ ๋žญํ‚น ์กฐํšŒ (์ฃผ๋ฌธ์ˆ˜ ๊ธฐ์ค€ ์ •๋ ฌ)
*/
List<ProductMetricsMonthly> findByYearAndMonthOrderByOrderCountDesc(int year, int month, int limit);

/**
* ํŠน์ • ๋…„๋„/์›”์˜ ๋žญํ‚น ์กฐํšŒ (Score ๊ธฐ์ค€ ์ •๋ ฌ)
*/
List<ProductMetricsMonthly> findByYearAndMonthOrderByCompositeScoreDesc(int year, int month, int limit);

/**
* ํŠน์ • ์ƒํ’ˆ์˜ ์›”๊ฐ„ ๋žญํ‚น ์กฐํšŒ
*/
Optional<ProductMetricsMonthly> findByYearAndMonthAndProductId(int year, int month, Long productId);

/**
* ํŠน์ • ๋…„๋„/์›”์˜ ์ „์ฒด ์ƒํ’ˆ ์ˆ˜
*/
long countByYearAndMonth(int year, int month);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.loopers.domain.metrics;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.Immutable;

import java.time.LocalDate;
import java.time.ZonedDateTime;

/**
* ์ฃผ๊ฐ„ ์ƒํ’ˆ ์ง‘๊ณ„ Materialized View (์ฝ๊ธฐ ์ „์šฉ)
* commerce-collector์—์„œ ์ƒ์„ฑํ•œ ์ง‘๊ณ„ ๋ฐ์ดํ„ฐ ์กฐํšŒ์šฉ
*/
@Entity
@Table(name = "mv_product_metrics_weekly")
@Getter
@NoArgsConstructor
@Immutable // ์ฝ๊ธฐ ์ „์šฉ
public class ProductMetricsWeekly {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "product_id", nullable = false)
private Long productId;

@Column(name = "year", nullable = false)
private Integer year;

@Column(name = "week", nullable = false)
private Integer week;

@Column(name = "period_start_date", nullable = false)
private LocalDate periodStartDate;

@Column(name = "period_end_date", nullable = false)
private LocalDate periodEndDate;

@Column(name = "total_like_count", nullable = false)
private Long totalLikeCount;

@Column(name = "total_view_count", nullable = false)
private Long totalViewCount;

@Column(name = "total_order_count", nullable = false)
private Long totalOrderCount;

@Column(name = "aggregated_at")
private ZonedDateTime aggregatedAt;

@Column(name = "created_at")
private ZonedDateTime createdAt;

@Column(name = "updated_at")
private ZonedDateTime updatedAt;

/**
* ์ข…ํ•ฉ ์ ์ˆ˜ ๊ณ„์‚ฐ (๊ฐ€์ค‘์น˜ ์ ์šฉ)
* Score = (like * 0.2) + (view * 0.1) + (order * 0.6)
*/
public double calculateCompositeScore() {
return (totalLikeCount * 0.2) + (totalViewCount * 0.1) + (totalOrderCount * 0.6);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.loopers.domain.metrics;

import java.util.List;
import java.util.Optional;

public interface ProductMetricsWeeklyRepository {
/**
* ํŠน์ • ๋…„๋„/์ฃผ์ฐจ์˜ ๋žญํ‚น ์กฐํšŒ (์ข‹์•„์š” ๊ธฐ์ค€ ์ •๋ ฌ)
*/
List<ProductMetricsWeekly> findByYearAndWeekOrderByLikeCountDesc(int year, int week, int limit);

/**
* ํŠน์ • ๋…„๋„/์ฃผ์ฐจ์˜ ๋žญํ‚น ์กฐํšŒ (์กฐํšŒ์ˆ˜ ๊ธฐ์ค€ ์ •๋ ฌ)
*/
List<ProductMetricsWeekly> findByYearAndWeekOrderByViewCountDesc(int year, int week, int limit);

/**
* ํŠน์ • ๋…„๋„/์ฃผ์ฐจ์˜ ๋žญํ‚น ์กฐํšŒ (์ฃผ๋ฌธ์ˆ˜ ๊ธฐ์ค€ ์ •๋ ฌ)
*/
List<ProductMetricsWeekly> findByYearAndWeekOrderByOrderCountDesc(int year, int week, int limit);

/**
* ํŠน์ • ๋…„๋„/์ฃผ์ฐจ์˜ ๋žญํ‚น ์กฐํšŒ (score ๊ธฐ์ค€ ์ •๋ ฌ)
*/
List<ProductMetricsWeekly> findByYearAndWeekOrderByCompositeScoreDesc(int year, int week, int limit);

/**
* ํŠน์ • ์ƒํ’ˆ์˜ ์ฃผ๊ฐ„ ๋žญํ‚น ์กฐํšŒ
*/
Optional<ProductMetricsWeekly> findByYearAndWeekAndProductId(int year, int week, Long productId);

/**
* ํŠน์ • ๋…„๋„/์ฃผ์ฐจ์˜ ์ „์ฒด ์ƒํ’ˆ ์ˆ˜
*/
long countByYearAndWeek(int year, int week);
}
Loading