33import com .movelog .domain .record .domain .Keyword ;
44import com .movelog .domain .record .domain .Record ;
55import com .movelog .domain .record .domain .repository .RecordRepository ;
6+ import com .movelog .domain .record .dto .response .AllUserKeywordStatsRes ;
67import com .movelog .domain .record .dto .response .MyKeywordStatsRes ;
78import com .movelog .domain .record .dto .response .RecommendKeywordInStatsRes ;
89import com .movelog .domain .record .dto .response .SearchKeywordInStatsRes ;
1516import com .movelog .global .config .security .token .UserPrincipal ;
1617import lombok .RequiredArgsConstructor ;
1718import lombok .extern .slf4j .Slf4j ;
18- import org .springframework .data .jpa .repository .Query ;
1919import org .springframework .stereotype .Service ;
2020import org .springframework .transaction .annotation .Transactional ;
2121
@@ -54,6 +54,7 @@ public List<SearchKeywordInStatsRes> searchKeywordInStats(UserPrincipal userPrin
5454
5555 }
5656
57+ // 사용자 개인의 특정 키워드 통계 조회
5758 public MyKeywordStatsRes getMyKeywordStatsRes (UserPrincipal userPrincipal , Long keywordId ) {
5859 validUserById (userPrincipal );
5960 Keyword keyword = validKeywordById (keywordId );
@@ -64,35 +65,35 @@ public MyKeywordStatsRes getMyKeywordStatsRes(UserPrincipal userPrincipal, Long
6465
6566 return MyKeywordStatsRes .builder ()
6667 .noun (keyword .getKeyword ())
67- .count (keywordRecordCount (keywordId ))
68- .lastRecordedAt (getLastRecordedAt (keywordId ))
69- .avgDailyRecord (calculateAverageDailyRecords (keywordId ))
70- .avgWeeklyRecord (getAvgWeeklyRecord (keywordId ))
68+ .count (keywordRecordCountByKeywordId (keywordId ))
69+ .lastRecordedAt (getLastRecordedAtByKeywordId (keywordId ))
70+ .avgDailyRecord (calculateAverageDailyRecordsByKeywordId (keywordId ))
71+ .avgWeeklyRecord (getAvgWeeklyRecordByKeywordId (keywordId ))
7172 .build ();
7273 }
7374
7475
7576 // 키워드 내 기록 개수를 반환
76- private int keywordRecordCount (Long keywordId ){
77+ private int keywordRecordCountByKeywordId (Long keywordId ){
7778 Keyword keyword = validKeywordById (keywordId );
7879 return keyword .getRecords ().size ();
7980 }
8081
8182 // 키워드 내 기록이 많은 순서대로 정렬
8283 private List <Keyword > sortKeywordByRecordCount (List <Keyword > keywords ) {
8384 return keywords .stream ()
84- .sorted ((k1 , k2 ) -> keywordRecordCount (k2 .getKeywordId ()) - keywordRecordCount (k1 .getKeywordId ()))
85+ .sorted ((k1 , k2 ) -> keywordRecordCountByKeywordId (k2 .getKeywordId ()) - keywordRecordCountByKeywordId (k1 .getKeywordId ()))
8586 .toList ();
8687 }
8788
8889 // 키워드의 마지막 기록 시간을 반환
89- private LocalDateTime getLastRecordedAt (Long keywordId ) {
90+ private LocalDateTime getLastRecordedAtByKeywordId (Long keywordId ) {
9091 Record record = recordRepository .findTopByKeywordKeywordIdOrderByActionTimeDesc (keywordId );
9192 return record .getActionTime ();
9293 }
9394
9495 // 키워드의 일일 평균 기록 수를 반환
95- public double calculateAverageDailyRecords (Long keywordId ) {
96+ public double calculateAverageDailyRecordsByKeywordId (Long keywordId ) {
9697 List <Object []> results = recordRepository .findKeywordRecordCountsByDate (keywordId );
9798
9899 // 총 기록 수와 기록된 날짜 수 계산
@@ -109,7 +110,7 @@ public double calculateAverageDailyRecords(Long keywordId) {
109110 }
110111
111112 // 키워드의 최근 7일간 평균 기록 수를 반환
112- public double getAvgWeeklyRecord (Long keywordId ) {
113+ public double getAvgWeeklyRecordByKeywordId (Long keywordId ) {
113114 Keyword keyword = validKeywordById (keywordId );
114115 List <Record > records = recordRepository .findTop5ByKeywordOrderByActionTimeDesc (keyword );
115116
@@ -141,6 +142,73 @@ public List<RecommendKeywordInStatsRes> getRecommendKeywords(UserPrincipal userP
141142 .toList ();
142143 }
143144
145+
146+ // 전체 사용자의 특정 키워드 통계 조회
147+ public AllUserKeywordStatsRes getAllUserKeywordStats (UserPrincipal userPrincipal , String keyword ) {
148+ validUserById (userPrincipal );
149+ // 해당 키워드에 대한 전체 사용자의 기록 목록
150+ List <Record > records = recordRepository .findAllByKeyword (keyword );
151+
152+ return AllUserKeywordStatsRes .builder ()
153+ .noun (keyword )
154+ .count (records .size ())
155+ .lastRecordedAt (getLastRecordedAtByRecords (records ))
156+ .avgDailyRecord (calculateAverageDailyRecordsByRecords (keyword ))
157+ .avgWeeklyRecord (getAvgWeeklyRecordByRecords (records ))
158+ .build ();
159+ }
160+
161+ // 키워드의 마지막 기록 시간을 반환
162+ private LocalDateTime getLastRecordedAtByRecords (List <Record > records ) {
163+ return records .stream ()
164+ .map (Record ::getActionTime )
165+ .max (LocalDateTime ::compareTo )
166+ .orElse (null );
167+ }
168+
169+ // 키워드의 일일 평균 기록 수를 반환
170+ private double calculateAverageDailyRecordsByRecords (String keyword ) {
171+ /// 날짜별 기록 수 계산
172+ List <Object []> results = recordRepository .findRecordCountsByKeywordGroupedByDate (keyword );
173+
174+ // 총 기록 수 계산
175+ long totalRecords = results .stream ()
176+ .mapToLong (row -> ((Long ) row [1 ])) // COUNT(r)
177+ .sum ();
178+
179+ // 기록된 날짜 수 계산
180+ long days = results .stream ()
181+ .map (row -> (java .sql .Date ) row [0 ]) // DATE(r.actionTime)
182+ .distinct ()
183+ .count ();
184+
185+ // 일일 평균 계산
186+ double result = days == 0 ? 0 : (double ) totalRecords / days ;
187+
188+ // 소수점 둘째 자리에서 반올림하여 반환
189+ return roundToTwoDecimal (result );
190+ }
191+
192+ // 키워드의 최근 7일간 평균 기록 수를 반환
193+ private double getAvgWeeklyRecordByRecords (List <Record > records ) {
194+ // 최근 7일간 기록 조회 (날짜 기준 오름차순 정렬 후 최근 7일 간의 기록만 추출) -> 하루에도 여러 개의 기록이 있을 수 있음
195+ LocalDateTime today = LocalDateTime .now ();
196+ LocalDateTime weekAgo = today .minusDays (7 );
197+ List <Record > recentRecords = records .stream ()
198+ .filter (record -> record .getActionTime ().isAfter (weekAgo ))
199+ .toList ();
200+
201+ // 최근 7일간 기록 수 계산
202+ long totalRecords = recentRecords .size ();
203+ long days = 7 ;
204+
205+ // 일일 평균 계산
206+ double result = days == 0 ? 0 : (double ) totalRecords / days ;
207+ // 소수점 둘째 자리에서 반올림하여 반환
208+ return roundToTwoDecimal (result );
209+ }
210+
211+
144212 private User validUserById (UserPrincipal userPrincipal ) {
145213 Optional <User > userOptional = userService .findById (userPrincipal .getId ());
146214 // Optional<User> userOptional = userRepository.findById(5L);
0 commit comments