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
@@ -0,0 +1,17 @@
package com.matzip.place.application.port;

import com.matzip.place.api.response.PlaceRankingResponseDto;
import com.matzip.place.domain.Campus;

import java.time.LocalDate;
import java.util.List;
import java.util.Optional;

public interface RankingTempStore {

Optional<List<PlaceRankingResponseDto>> get(LocalDate date, Campus campus);

void set(LocalDate date, Campus campus, List<PlaceRankingResponseDto> rankingResponseDtos);

void remove(LocalDate date, Campus campus);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
import com.matzip.place.api.response.CategoryPlaceResponseDto;
import com.matzip.place.api.response.MapSearchResponseDto;
import com.matzip.place.api.response.PlaceDetailResponseDto;
import com.matzip.place.application.port.RankingTempStore;
import com.matzip.place.domain.entity.*;
import com.matzip.place.api.response.PlaceRankingResponseDto;
import com.matzip.place.domain.*;
import com.matzip.place.infra.repository.*;
import com.matzip.place.dto.CategoryDto;
import com.matzip.place.dto.TagDto;
import com.matzip.user.domain.User;
import com.matzip.user.infra.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.PageRequest;
Expand All @@ -39,8 +39,10 @@ public class PlaceReadService {
private final PlaceLikeRepository placeLikeRepository;
private final UserRepository userRepository;
private final ViewCountService viewCountService;
private final RankingTempStore rankingTempStore;

private static final int RANKING_SIZE = 10;
private static final int MINIMUM_RANKING_SIZE = 3;

@Transactional
public PlaceDetailResponseDto getPlaceDetail(Long placeId, Long userId) {
Expand Down Expand Up @@ -95,18 +97,17 @@ public List<MapSearchResponseDto> findPlacesInMapBounds(MapSearchRequestDto requ

public List<PlaceRankingResponseDto> getRanking(Campus campus, String sort) {
if ("views".equals(sort)) {
return getDailyRankingByViews(campus);
return getRankingByViewsWithFallback(campus);
}

// TODO: 찜 많은 맛집 기능 구현 후 추가하기
return getDailyRankingByViews(campus);
return getRankingByViewsWithFallback(campus);
}

private List<PlaceRankingResponseDto> getDailyRankingByViews(Campus campus) {
LocalDate today = LocalDate.now();
public List<PlaceRankingResponseDto> getDailyRankingByViews(Campus campus, LocalDate date) {
Pageable topN = PageRequest.of(0, RANKING_SIZE);

List<DailyViewCount> dailyRankings = dailyViewCountRepository.findDailyRankingByCampus(campus, today, topN);
List<DailyViewCount> dailyRankings = dailyViewCountRepository.findDailyRankingByCampus(campus, date, topN);

return dailyRankings.stream()
.map(dailyViewCount -> {
Expand All @@ -117,6 +118,18 @@ private List<PlaceRankingResponseDto> getDailyRankingByViews(Campus campus) {
.collect(Collectors.toList());
}

private List<PlaceRankingResponseDto> getRankingByViewsWithFallback(Campus campus) {
LocalDate today = LocalDate.now();
List<PlaceRankingResponseDto> todaysRanking = getDailyRankingByViews(campus, today);

if (todaysRanking.size() < MINIMUM_RANKING_SIZE) {
LocalDate yesterday = today.minusDays(1);
return rankingTempStore.get(yesterday, campus)
.orElseGet(() -> getDailyRankingByViews(campus, yesterday));
}
return todaysRanking;
}

/**
* Place의 연관 데이터를 조회하는 공통 메서드
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.matzip.place.infra.cache;

import com.matzip.place.api.response.PlaceRankingResponseDto;
import com.matzip.place.application.port.RankingTempStore;
import com.matzip.place.domain.Campus;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class PlaceRankingTempStoreMemory implements RankingTempStore {

private final Map<String, List<PlaceRankingResponseDto>> store = new ConcurrentHashMap<>();


@Override
public Optional<List<PlaceRankingResponseDto>> get(LocalDate date, Campus campus) {
String key = generateKey(date, campus);
return Optional.ofNullable(store.get(key));
}

@Override
public void set(LocalDate date, Campus campus, List<PlaceRankingResponseDto> rankingResponseDtos) {
String key = generateKey(date, campus);
store.put(key, rankingResponseDtos);
}

@Override
public void remove(LocalDate date, Campus campus) {
String key = generateKey(date, campus);
store.remove(key);
}

private String generateKey(LocalDate date, Campus campus) {
return date.toString() + ":" + campus.name();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.matzip.place.infra.scheduler;

import com.matzip.place.api.response.PlaceRankingResponseDto;
import com.matzip.place.application.port.RankingTempStore;
import com.matzip.place.application.service.PlaceReadService;
import com.matzip.place.domain.Campus;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;

@Component
@RequiredArgsConstructor
public class PlaceRankingScheduler {

private final PlaceReadService placeReadService;
private final RankingTempStore rankingTempStore;

@Scheduled(cron = "0 5 0 * * *")
public void cachePreviousDayPlaceRankings() {
LocalDate yesterday = LocalDate.now().minusDays(1);
LocalDate twoDaysAgo = LocalDate.now().minusDays(2);

Arrays.stream(Campus.values()).forEach(campus -> {
List<PlaceRankingResponseDto> ranking = placeReadService.getDailyRankingByViews(campus, yesterday);
rankingTempStore.set(yesterday, campus, ranking);

rankingTempStore.remove(twoDaysAgo, campus);
});
}
}