Skip to content

Commit 76c6ee7

Browse files
committed
feat: 관리자 LLM 지출분석 통계 조회 성능 향상
1 parent 208e3ae commit 76c6ee7

4 files changed

Lines changed: 68 additions & 34 deletions

File tree

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,13 @@
11
package store.lastdance.dto.admin;
22

3-
import java.time.LocalDateTime;
4-
5-
63
import java.util.List;
74

85
public record ExpenseAnalyzerFeedbackStatsDTO(
96
long totalFeedbacks,
10-
long upCount,
11-
long downCount,
7+
Long upCount,
8+
Long downCount,
129
double satisfactionRate,
1310
List<FeedbackTrendDTO> trends
1411
) {
15-
public record FeedbackTrendDTO(
16-
String date,
17-
long totalCount,
18-
long upCount,
19-
long downCount
20-
) {}
2112
}
13+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package store.lastdance.dto.admin;
2+
3+
public record FeedbackTrendDTO(
4+
int year,
5+
int month,
6+
int day,
7+
Long totalCount,
8+
Long upCount,
9+
Long downCount
10+
) {}

src/main/java/store/lastdance/repository/expense/ExpenseAnalysisHistoryRepository.java

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44
import org.springframework.data.domain.Pageable;
55
import org.springframework.data.jpa.domain.Specification;
66
import org.springframework.data.jpa.repository.JpaRepository;
7+
import org.springframework.data.jpa.repository.Query;
8+
import org.springframework.data.repository.query.Param;
79
import store.lastdance.domain.expense.ExpenseAnalysisHistory;
810
import store.lastdance.domain.user.User;
11+
import store.lastdance.dto.admin.ExpenseAnalyzerFeedbackStatsDTO;
912

1013
import java.time.LocalDateTime;
1114
import java.util.List;
@@ -21,4 +24,46 @@ public interface ExpenseAnalysisHistoryRepository extends JpaRepository<ExpenseA
2124
List<ExpenseAnalysisHistory> findByCreatedAtBetween(LocalDateTime startDate, LocalDateTime endDate);
2225

2326
Page<ExpenseAnalysisHistory> findAll(Specification<ExpenseAnalysisHistory> spec, Pageable pageable);
24-
}
27+
28+
@Query("SELECT new store.lastdance.dto.admin.ExpenseAnalyzerFeedbackStatsDTO(" +
29+
" COALESCE(SUM(CASE WHEN e.up = true OR e.down = true THEN 1 ELSE 0 END), 0L), " +
30+
" COALESCE(SUM(CASE WHEN e.up = true THEN 1 ELSE 0 END), 0L), " +
31+
" COALESCE(SUM(CASE WHEN e.down = true THEN 1 ELSE 0 END), 0L), " +
32+
" 0.0, " + // satisfactionRate will be calculated in service layer
33+
" null) " + // trends will be calculated in service layer
34+
"FROM ExpenseAnalysisHistory e")
35+
ExpenseAnalyzerFeedbackStatsDTO getFeedbackStatsSummary();
36+
37+
@Query("SELECT new store.lastdance.dto.admin.ExpenseAnalyzerFeedbackStatsDTO(" +
38+
" COALESCE(SUM(CASE WHEN e.up = true OR e.down = true THEN 1 ELSE 0 END), 0L), " +
39+
" COALESCE(SUM(CASE WHEN e.up = true THEN 1 ELSE 0 END), 0L), " +
40+
" COALESCE(SUM(CASE WHEN e.down = true THEN 1 ELSE 0 END), 0L), " +
41+
" 0.0, " + // satisfactionRate will be calculated in service layer
42+
" null) " + // trends will be calculated in service layer
43+
"FROM ExpenseAnalysisHistory e WHERE e.createdAt BETWEEN :startDate AND :endDate")
44+
ExpenseAnalyzerFeedbackStatsDTO getFeedbackStatsSummaryBetween(@Param("startDate") LocalDateTime startDate, @Param("endDate") LocalDateTime endDate);
45+
@Query("SELECT new store.lastdance.dto.admin.FeedbackTrendDTO(" +
46+
" YEAR(e.createdAt), " +
47+
" MONTH(e.createdAt), " +
48+
" DAY(e.createdAt), " +
49+
" COUNT(e), " +
50+
" COALESCE(SUM(CASE WHEN e.up = true THEN 1 ELSE 0 END), 0L), " +
51+
" COALESCE(SUM(CASE WHEN e.down = true THEN 1 ELSE 0 END), 0L)) " +
52+
"FROM ExpenseAnalysisHistory e " +
53+
"WHERE e.createdAt BETWEEN :startDate AND :endDate " +
54+
"GROUP BY YEAR(e.createdAt), MONTH(e.createdAt), DAY(e.createdAt) " +
55+
"ORDER BY YEAR(e.createdAt), MONTH(e.createdAt), DAY(e.createdAt)")
56+
List<store.lastdance.dto.admin.FeedbackTrendDTO> findFeedbackTrendsBetween(@Param("startDate") LocalDateTime startDate, @Param("endDate") LocalDateTime endDate);
57+
58+
@Query("SELECT new store.lastdance.dto.admin.FeedbackTrendDTO(" +
59+
" YEAR(e.createdAt), " +
60+
" MONTH(e.createdAt), " +
61+
" DAY(e.createdAt), " +
62+
" COUNT(e), " +
63+
" COALESCE(SUM(CASE WHEN e.up = true THEN 1 ELSE 0 END), 0L), " +
64+
" COALESCE(SUM(CASE WHEN e.down = true THEN 1 ELSE 0 END), 0L)) " +
65+
"FROM ExpenseAnalysisHistory e " +
66+
"GROUP BY YEAR(e.createdAt), MONTH(e.createdAt), DAY(e.createdAt) " +
67+
"ORDER BY YEAR(e.createdAt), MONTH(e.createdAt), DAY(e.createdAt)")
68+
List<store.lastdance.dto.admin.FeedbackTrendDTO> findFeedbackTrends();
69+
}

src/main/java/store/lastdance/service/admin/AdminServiceImpl.java

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -946,37 +946,24 @@ public ExpenseAnalyzerFeedbackStatsDTO getExpenseAnalyzerFeedbackStats(UUID user
946946

947947
validateAdmin(userId);
948948

949-
List<ExpenseAnalysisHistory> histories;
949+
ExpenseAnalyzerFeedbackStatsDTO statsSummary;
950+
List<FeedbackTrendDTO> trends;
951+
950952
if ("all".equalsIgnoreCase(period)) {
951-
histories = expenseAnalysisHistoryRepository.findAll();
953+
statsSummary = expenseAnalysisHistoryRepository.getFeedbackStatsSummary();
954+
trends = expenseAnalysisHistoryRepository.findFeedbackTrends();
952955
} else {
953956
LocalDateTime endDate = LocalDateTime.now();
954957
LocalDateTime startDate = parsePeriod(period, endDate);
955-
histories = expenseAnalysisHistoryRepository.findByCreatedAtBetween(startDate, endDate);
956-
}
957-
958-
if (histories.isEmpty()) {
959-
return new ExpenseAnalyzerFeedbackStatsDTO(0, 0, 0, 0.0, Collections.emptyList());
958+
statsSummary = expenseAnalysisHistoryRepository.getFeedbackStatsSummaryBetween(startDate, endDate);
959+
trends = expenseAnalysisHistoryRepository.findFeedbackTrendsBetween(startDate, endDate);
960960
}
961961

962-
long upCount = histories.stream().filter(h -> Boolean.TRUE.equals(h.getUp())).count();
963-
long downCount = histories.stream().filter(h -> Boolean.TRUE.equals(h.getDown())).count();
962+
long upCount = statsSummary.upCount() != null ? statsSummary.upCount() : 0L;
963+
long downCount = statsSummary.downCount() != null ? statsSummary.downCount() : 0L;
964964
long totalFeedbacks = upCount + downCount;
965965
double satisfactionRate = totalFeedbacks > 0 ? (double) upCount / totalFeedbacks * 100 : 0.0;
966966

967-
Map<String, List<ExpenseAnalysisHistory>> groupedByDate = histories.stream()
968-
.collect(Collectors.groupingBy(h -> h.getCreatedAt().toLocalDate().toString()));
969-
970-
List<ExpenseAnalyzerFeedbackStatsDTO.FeedbackTrendDTO> trends = groupedByDate.entrySet().stream()
971-
.map(entry -> {
972-
long dailyUpCount = entry.getValue().stream().filter(h -> Boolean.TRUE.equals(h.getUp())).count();
973-
long dailyDownCount = entry.getValue().stream().filter(h ->
974-
Boolean.TRUE.equals(h.getDown())).count();
975-
return new ExpenseAnalyzerFeedbackStatsDTO.FeedbackTrendDTO(entry.getKey(), dailyUpCount + dailyDownCount, dailyUpCount, dailyDownCount);
976-
})
977-
.sorted(Comparator.comparing(ExpenseAnalyzerFeedbackStatsDTO.FeedbackTrendDTO::date))
978-
.collect(Collectors.toList());
979-
980967
return new ExpenseAnalyzerFeedbackStatsDTO(totalFeedbacks, upCount, downCount, satisfactionRate, trends);
981968
}
982969

0 commit comments

Comments
 (0)