Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature] 데이터 파이프라인 complete #34

Merged
merged 3 commits into from
Nov 10, 2023
Merged
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
@@ -1,10 +1,7 @@
package com.locationbasedfoodieservice.rawrestaurant.entity;

import com.locationbasedfoodieservice.restaurant.entity.Restaurant;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
Expand All @@ -18,6 +15,8 @@
@NoArgsConstructor
@AllArgsConstructor
@DynamicUpdate
@Table(uniqueConstraints =
{@UniqueConstraint(columnNames = {"bizplcNm", "refineZipCd"})})
public class RawRestaurant {

@Id
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.locationbasedfoodieservice.rawrestaurant.scheduler;

public enum DataType {
KIMBOB("Genrestrtlunch"),
CAFE("Genrestrtcate"),
CHINESE("Genrestrtchifood"),
JAPANESE("Genrestrtjpnfood"),
SOUP("Genrestrtsoup"),
FAST_FOOD("Genrestrtfastfood");

private String url;

DataType(String url) {
this.url = url;
}

public String getUrl() {
return url;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@

import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;

@Slf4j(topic = "Open Api Scheduler Log")
@Slf4j(topic = "Open API Scheduler Log")
@Component
@RequiredArgsConstructor
@Transactional
public class RawKimbobScheduler {
public class RawRestaurantScheduler {

private final RestTemplate restTemplate;
private final RawRestaurantRepository rawRestaurantRepository;

Expand All @@ -38,19 +39,33 @@ public class RawKimbobScheduler {
private Long dataCount;
private Long batchSize = 999L; // 한 번의 API 요청에 999개까지의 데이터만을 받아올 수 있습니다.

// 크론 스케줄링
// 첫 번째 필드: 초 (0-59)
// 두 번째 필드: 분 (0-59)
// 세 번째 필드: 시간 (0-23)
// 네 번째 필드: 일 (1-31)
// 다섯 번째 필드: 월 (1-12)
// 여섯 번째 필드: 요일 (0-6, 일요일부터 토요일까지, 일요일=0 또는 7)
/**
* 크론 스케줄링
* 첫 번째 필드: 초 (0-59)
* 두 번째 필드: 분 (0-59)
* 세 번째 필드: 시간 (0-23)
* 네 번째 필드: 일 (1-31)
* 다섯 번째 필드: 월 (1-12)
* 여섯 번째 필드: 요일 (0-6, 일요일부터 토요일까지, 일요일=0 또는 7)
*/

// 데이터 총 개수를 가져와서 dataCount에 넣어줍니다.
@Scheduled(cron = "0 0 4 * * 6")
public void countingData() {
public void updateRawRestaurant() {
for (DataType type : DataType.values()) {
countData(type.getUrl());
updateData(type.getUrl());
}
Comment on lines +54 to +58
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

공통된 특징을 찾아 type으로 for문을 돌면서 데이터를 관리하는건 좋은 아이디어 같습니다

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니다!

}

/**
* 데이터 총 개수를 가져옵니다.
*
* @param type 업장종류(김밥, 카페, 일식, ...)
*/
private void countData(String type) {
URI uri = UriComponentsBuilder
.fromUriString("https://openapi.gg.go.kr/Genrestrtlunch")
.fromUriString("https://openapi.gg.go.kr/" + type)
.queryParam("KEY", API_KEY)
.queryParam("Type", "json")
.queryParam("pSize", 1)
Expand All @@ -62,23 +77,26 @@ public void countingData() {
ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class);

dataCount = new JSONObject(responseEntity.getBody())
.getJSONArray("Genrestrtlunch").getJSONObject(0)
.getJSONArray(type).getJSONObject(0)
.getJSONArray("head").getJSONObject(0)
.getLong("list_total_count");

log.info("dataCount = " + dataCount);
}

// 데이터 총 갯수에 맞춰 for문을 돌면서 데이터를 가져옵니다.
// (데이터를 한 번에 1000개 이상으로 가져오지 못하기 때문)
@Scheduled(cron = "30 0 4 * * 6") // 토요일 새벽 4시 업데이트
public void updateKimbob() {
/**
* 데이터 총 개수에 맞춰 for문을 돌면서 데이터를 가져옵니다.
*
* @param type 업장종류(김밥, 카페, 일식, ...)
*/
private void updateData(String type) {
long page = (dataCount / batchSize) + 1;

log.info("Kimbob Update Scheduling Start");
log.info(type + " Update Scheduling Start");

for (int i = 1; i <= page; i++) {
URI uri = UriComponentsBuilder
.fromUriString("https://openapi.gg.go.kr/Genrestrtlunch")
.fromUriString("https://openapi.gg.go.kr/" + type)
.queryParam("KEY", API_KEY)
.queryParam("Type", "json")
.queryParam("pIndex", i)
Expand All @@ -91,22 +109,22 @@ public void updateKimbob() {
ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class);

JSONArray rawRestaurants = new JSONObject(responseEntity.getBody())
.getJSONArray("Genrestrtlunch").getJSONObject(1)
.getJSONArray(type).getJSONObject(1)
.getJSONArray("row");

updateOrSaveIfNotExists(rawRestaurants);
}
log.info("Kimbob Update Scheduling End");
log.info(type + " Update Scheduling End");
}

/**
* JSON 배열 raw데이터들을 받아서 확인 후 없으면 저장 있으면 업데이트하는 메서드입니다.
* JSON 배열 raw데이터들을 받아서 확인 후 없으면 저장, 있으면 업데이트하는 메서드입니다.
*
* @param rawRestaurants
*/
private void updateOrSaveIfNotExists(JSONArray rawRestaurants) {
// DB에 존재하지 않을 경우 list에 담아두고 한꺼번에 저장하기 위한 용도입니다.
List<RawRestaurant> saveRawDataList = new ArrayList<>();
Map<String, RawRestaurant> saveRawDataList = new HashMap<>();

for (int j = 0; j < rawRestaurants.length(); j++) {
JSONObject rawRestaurant = rawRestaurants.getJSONObject(j);
Expand All @@ -124,18 +142,18 @@ private void updateOrSaveIfNotExists(JSONArray rawRestaurants) {
targetRawRestaurant -> targetRawRestaurant.update(rawRestaurant),
() -> {
RawRestaurant newRawRestaurant = from(rawRestaurant);
saveRawDataList.add(newRawRestaurant);
saveRawDataList.put(BIZPLC_NM + REFINE_ZIP_CD, newRawRestaurant);
}
);
}
rawRestaurantRepository.saveAll(saveRawDataList);
rawRestaurantRepository.saveAll(saveRawDataList.values());
}

/**
* JSON을 객체화해주는 메서드입니다.
*
* @param rawRestaurant
* @return
* @param rawRestaurant JSON
* @return RawRestaurant 객체
*/
public RawRestaurant from(JSONObject rawRestaurant) {
return RawRestaurant.builder()
Expand Down
Loading