Skip to content

Commit 0b473d6

Browse files
authored
Merge pull request #149 from prgrms-aibe-devcourse/refactor/expense-LLM
refactor : 관리자 LLM 지출분석 analyzer 성능 향상
2 parents 8e617d5 + c9360f8 commit 0b473d6

4 files changed

Lines changed: 46 additions & 10 deletions

File tree

src/main/java/store/lastdance/domain/expense/ExpenseAnalysisHistory.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
import java.time.LocalDate;
1414
@Entity
1515
@Getter
16-
@Table(name = "expense_analysis_history")
16+
@Table(name = "expense_analysis_history", indexes = {
17+
@Index(name = "idx_created_at", columnList = "created_At")
18+
})
1719
@NoArgsConstructor(access = AccessLevel.PROTECTED)
1820
@EntityListeners(AuditingEntityListener.class)
1921
public class ExpenseAnalysisHistory extends BaseTimeEntity {

src/main/java/store/lastdance/domain/user/User.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
@Getter
1212
@Setter
1313
@Entity
14-
@Table(name = "users")
14+
@Table(name = "users", indexes = {
15+
@Index(name = "idx_user_email", columnList = "email"),
16+
@Index(name = "idx_user_nickname", columnList = "nickname")
17+
})
1518
@NoArgsConstructor(access = AccessLevel.PROTECTED)
1619
public class User extends BaseTimeEntity {
1720
@Id

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,30 @@
33
import org.springframework.data.domain.Page;
44
import org.springframework.data.domain.Pageable;
55
import org.springframework.data.jpa.domain.Specification;
6+
import org.springframework.data.jpa.repository.EntityGraph;
67
import org.springframework.data.jpa.repository.JpaRepository;
8+
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
79
import org.springframework.data.jpa.repository.Query;
810
import org.springframework.data.repository.query.Param;
911
import store.lastdance.domain.expense.ExpenseAnalysisHistory;
1012
import store.lastdance.domain.user.User;
13+
import store.lastdance.dto.admin.AdminExpenseAnalyzerHistoryDTO;
1114
import store.lastdance.dto.admin.ExpenseAnalyzerFeedbackStatsDTO;
1215

1316
import java.time.LocalDateTime;
1417
import java.util.List;
1518
import java.util.UUID;
1619

17-
public interface ExpenseAnalysisHistoryRepository extends JpaRepository<ExpenseAnalysisHistory, Long> {
20+
public interface ExpenseAnalysisHistoryRepository extends JpaRepository<ExpenseAnalysisHistory, Long>,
21+
JpaSpecificationExecutor<ExpenseAnalysisHistory> {
22+
23+
@EntityGraph(attributePaths = "user")
24+
Page<ExpenseAnalysisHistory> findAll(Specification<ExpenseAnalysisHistory> spec, Pageable pageable);
25+
26+
@Query("SELECT new store.lastdance.dto.admin.AdminExpenseAnalyzerHistoryDTO(" +
27+
"eah.id, eah.user.email, eah.user.nickname, eah.createdAt, eah.up, eah.down) " +
28+
"FROM ExpenseAnalysisHistory eah JOIN eah.user u")
29+
Page<AdminExpenseAnalyzerHistoryDTO> findHistoryProjection(Specification<ExpenseAnalysisHistory> spec, Pageable pageable);
1830

1931
// 특정 사용자의 모든 분석 내역을 최신순으로 조회
2032
List<ExpenseAnalysisHistory> findByUserOrderByCreatedAtDesc(User user);
@@ -23,7 +35,6 @@ public interface ExpenseAnalysisHistoryRepository extends JpaRepository<ExpenseA
2335

2436
List<ExpenseAnalysisHistory> findByCreatedAtBetween(LocalDateTime startDate, LocalDateTime endDate);
2537

26-
Page<ExpenseAnalysisHistory> findAll(Specification<ExpenseAnalysisHistory> spec, Pageable pageable);
2738

2839
@Query("SELECT new store.lastdance.dto.admin.ExpenseAnalyzerFeedbackStatsDTO(" +
2940
" COALESCE(SUM(CASE WHEN e.up = true OR e.down = true THEN 1 ELSE 0 END), 0L), " +

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

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,9 @@ public AiJudgmentStatsDTO getAiJudgmentStats(UUID userId, String period) {
939939
return new AiJudgmentStatsDTO(satisfactionRate, dissatisfactionCount, trends);
940940
}
941941

942+
/**
943+
* LLM 지출분석 피드백 통계 조회
944+
*/
942945
@Override
943946
@Transactional(readOnly = true)
944947
public ExpenseAnalyzerFeedbackStatsDTO getExpenseAnalyzerFeedbackStats(UUID userId, String period) {
@@ -967,6 +970,9 @@ public ExpenseAnalyzerFeedbackStatsDTO getExpenseAnalyzerFeedbackStats(UUID user
967970
return new ExpenseAnalyzerFeedbackStatsDTO(totalFeedbacks, upCount, downCount, satisfactionRate, trends);
968971
}
969972

973+
/**
974+
* LLM 지출분석 내역 조회
975+
*/
970976
@Override
971977
public AdminExpenseAnalyzerHistoryResponseDTO getExpenseAnalyzerHistory(UUID userId, int page, int limit, String search, String rating, String dateFrom, String dateTo) {
972978
log.info("LLM 지출분석 내역 조회 : userId={}, page={}, limit={}, search={}, rating={}, dateFrom={}, dateTo={}",userId,page,limit,search,rating,dateFrom,dateTo);
@@ -977,11 +983,9 @@ public AdminExpenseAnalyzerHistoryResponseDTO getExpenseAnalyzerHistory(UUID use
977983

978984
Specification<ExpenseAnalysisHistory> spec = createExpenseAnalysisHistorySpecification(search,rating, dateFrom, dateTo);
979985

980-
Page<ExpenseAnalysisHistory> historyPage = expenseAnalysisHistoryRepository.findAll(spec, pageable);
986+
Page<AdminExpenseAnalyzerHistoryDTO> historyPage = expenseAnalysisHistoryRepository.findHistoryProjection(spec, pageable);
981987

982-
List<AdminExpenseAnalyzerHistoryDTO> historyDTOs = historyPage.getContent().stream()
983-
.map(AdminExpenseAnalyzerHistoryDTO::from)
984-
.collect(Collectors.toList());
988+
List<AdminExpenseAnalyzerHistoryDTO> historyDTOs = historyPage.getContent();
985989

986990
PaginationDTO pagination = new PaginationDTO(
987991
page,
@@ -994,14 +998,23 @@ public AdminExpenseAnalyzerHistoryResponseDTO getExpenseAnalyzerHistory(UUID use
994998
return new AdminExpenseAnalyzerHistoryResponseDTO(historyDTOs, pagination);
995999
}
9961000

1001+
/**
1002+
* 검색 조건에 따라 ExpenseAnalysisHistory 엔티티에 대한 JPA Specification을 생성합니다.
1003+
*
1004+
* @param search 검색어 (이메일 또는 닉네임)
1005+
* @param rating 피드백 평점 (UP 또는 DOWN)
1006+
* @param dateForm 시작 날짜
1007+
* @param dateTo 종료 날짜
1008+
* @return 생성된 Specification
1009+
*/
9971010
private Specification<ExpenseAnalysisHistory> createExpenseAnalysisHistorySpecification(String search, String rating, String dateForm, String dateTo) {
9981011
return (root, query, criteriaBuilder) -> {
9991012
List<Predicate> predicates = new ArrayList<>();
10001013

10011014
if (StringUtils.hasText(search)) {
10021015
predicates.add(criteriaBuilder.or(
1003-
criteriaBuilder.like(criteriaBuilder.lower(root.get("user").get("email")), "%" + search.toLowerCase() + "%"),
1004-
criteriaBuilder.like(criteriaBuilder.lower(root.get("user").get("nickname")), "%" + search.toLowerCase() + "%")
1016+
criteriaBuilder.like(root.get("user").get("email"), "%" + search + "%"),
1017+
criteriaBuilder.like(root.get("user").get("nickname"), "%" + search + "%")
10051018
));
10061019
}
10071020
if (StringUtils.hasText(rating)) {
@@ -1018,6 +1031,13 @@ private Specification<ExpenseAnalysisHistory> createExpenseAnalysisHistorySpecif
10181031
}
10191032

10201033
@Override
1034+
/**
1035+
* 특정 지출 분석 내역의 상세 정보를 조회합니다.
1036+
*
1037+
* @param userId 관리자 사용자 ID
1038+
* @param historyId 조회할 지출 분석 내역 ID
1039+
* @return 지출 분석 내역 상세 정보 DTO
1040+
*/
10211041
public ExpenseAnalysisHistoryDTO getExpenseAnalyzerHistoryDetail(UUID userId, Long historyId) {
10221042
log.info("LLM 지출분석 상세 조회 : userId={}, historyId={}",userId,historyId);
10231043

0 commit comments

Comments
 (0)