✏️ 학습내용
- LB (Load Balancing)
부하분산 또는 로드 밸런싱은 컴퓨터 네트워크 기술의 일종으로 둘 혹은 셋이상의 중앙처리장치 혹은 저장장치와 같은 컴퓨터 자원들에게 작업을 나누는 것을 의미한다. 이로써 가용성 및 응답시간을 최적화 시킬 수 있다.
$ cat /etc/nginx/sites-available/default
upstream serv {
# LB 구현
server localhost:8888 weight=50;
server localhost:7777 weight=50;
}
server {
listen 80;
location /
{
proxy_pass http://serv;
}
}
- ngnix
[실습]
$ mkdir -p tmp/tWeb/web1
$ mkdir -p tmp/tWeb/web2
$ vi tWeb/web1/index.html
<H1>WEB1:7777</H1>
$ vi tWeb/web2/index.html
<H1>WEB2:8888</H1>
$ nohup python -m http.server 7777 &
$ nohup python -m http.server 8888 &
$ cd /etc/nginx/sites-available
$ sudo vi default
upstream serv {
server localhost:7777;
server localhost:8888;
}
$ sudo service nginx restart
$ curl http://localhost
결과는 이렇게 번갈아가며 나온다.
*맥에서는 sites-available, sites-enables 디렉토리를 생성하고 available 아래 default 파일을 만들어 내용을 입력하고 심볼릭 링크를 통해 enables 와 연결시켜야했다. 그리고 nginx.conf 아래
http { ... include /opt/homebrew/etc/nginx/sites-enabled/*; ... }
추가해주어야함.
- ngrinder (부하발생기)
- 네이버에서 개발한 Enterpise 레벨 Java기반 성능 테스트 도구이다. Agent가 반드시 필요하며, Controller는 이를 조종하는 역할을 한다.
- java 버전 11로 변경 필요함
-컨트롤러 실행
$ cd app/ng/ngrinder-controller
$ java -Djava.io.tmpdir=/Users/sujinya/tmp/ng -jar ngrinder-controller-3.5.9-p1.war --port=8949
-에이전트 실행
$ cd app/ng/ngrinder-agent
$ ./run_agent.sh
처음에 start test 버튼이 먹히질 않았다.
해결법)
$ sudo rm -rf /Users/sujinya/.ngrinder
이렇게 설정하고 테스트를 수행해보았다.
127.0.0.1에 7777, 8888 포트가 번갈아가며 수행되는 상황이다.
TPS란?
TPS는 "Transactions Per Second"의 약자로, 초당 처리되는 트랜잭션의 수를 나타낸다. TPS는 시스템의 처리 성능을 나타내는 중요한 지표입니다. TPS가 높은 것이 일반적으로 좋다. 이유는 다음과 같다.
- 성능 향상:
- 높은 TPS는 시스템이 초당 많은 트랜잭션을 처리할 수 있음을 의미합니다. 이는 시스템의 성능이 뛰어나며, 더 많은 작업을 빠르게 수행할 수 있음을 나타냅니다.
- 효율성:
- 높은 TPS는 시스템 자원의 효율적 사용을 의미합니다. 자원을 잘 활용하여 많은 트랜잭션을 처리하는 것은 시스템의 전반적인 효율성을 높이는 데 기여합니다.
- 확장성:
- 높은 TPS는 시스템이 더 많은 요청을 처리할 수 있음을 나타내며, 이는 시스템이 더 높은 부하를 처리할 수 있도록 확장 가능함을 의미합니다. 대규모 트래픽을 처리해야 하는 상황에서 유리합니다.
- 사용자 경험 개선:
- 시스템의 TPS가 높으면 요청에 대한 응답 시간이 짧아지므로 사용자 경험이 개선됩니다. 이는 특히 사용자에게 실시간으로 반응해야 하는 애플리케이션에서 중요합니다.
- cpulimit
-리눅스에서 CPU 사용량을 제한하는 유틸리티입니다.
- cpulimit -l <비율> -p <PID>
- -l <비율>: 프로세스가 사용할 수 있는 최대 CPU 비율 (예: 50)
- -p <PID>: CPU 사용을 제한할 프로세스의 PID (프로세스 ID)
- FastAPI
HTTP 기반 서비스 API를 구축하기 위한 웹 프레임워크
우리가 저번에 영화진흥위원회 API를 사용해 데이터를 받은것 처럼 내가 데이터를 제공할 수 있는 기능(?)인 것 같다.
$ pdm venv create
$ source .venv/bin/activate
$ pdm init
$ pdm add "fastapi[standard]"
$ pdm add pandas pyarrow
$ vi src/ffapi/app.py
from typing import Union
from fastapi import FastAPI, HTTPException
import pandas as pd
app = FastAPI()
# 1번(전역)
#df = pd.read_parquet('/home/diginori/code/ffapi/data')
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/sample")
def sample_data():
# 2번(지역)
df = pd.read_parquet('/home/diginori/code/ffapi/data')
sample_df = df.sample(n=5)
r = sample_df.to_dict(orient='records')
return r
@app.get("/movie/{movie_cd}")
def movie_meta(movie_cd: str):
df = pd.read_parquet('/home/diginori/code/ffapi/data')
# df 에서 movieCd == movie_cd row 를 조회 df[['a'] === b] ...
meta_df = df[df['movieCd'] == movie_cd]
if meta_df.empty:
raise HTTPException(status_code=404, detail="영화를 찾을 수 없습니다")
# 조회된 데이터를 .to_dict() 로 만들어 아래에서 return
r = meta_df.iloc[0].to_dict()
return r
- /sample 엔드포인트는 Parquet 형식의 데이터를 읽어 DataFrame으로 변환합니다.
- df.sample(n=5)를 통해 DataFrame에서 무작위로 5개의 샘플을 추출합니다.
- to_dict(orient='records')를 사용하여 샘플 DataFrame을 JSON 형식으로 변환하여 반환합니다.
- /movie/{movie_cd} 엔드포인트는 URL 경로에서 영화 코드(movie_cd)를 받아 해당 영화의 메타데이터를 조회합니다.
- Parquet 파일에서 데이터를 읽고, df[df['movieCd'] == movie_cd]를 사용하여 movieCd가 일치하는 행을 필터링합니다.
- 필터링된 DataFrame이 비어 있으면 HTTP 404 오류를 발생시킵니다.
- 조회된 데이터의 첫 번째 행을 딕셔너리로 변환하여 JSON 응답으로 반환합니다.
# 실행
$ fastapi dev src/ffapi/app.py
app.py에서 df = pd.read_parquet('/home/diginori/code/ffapi/data') 코드를 전역변수로 처리하는 것과 지역변수로 처리하는 것 중 무엇이 더 성능에 좋을까?
나는 당연히 전역변수라고 생각했는데 챗지피티가
- 성능 최적화가 중요한 경우: 데이터 파일이 큰 경우나 읽기 작업이 빈번한 경우에는 1번 위치(전역)에서 파일을 읽어 메모리에 상주시키는 것이 성능 측면에서 더 유리할 수 있습니다. 그러나 이 경우 데이터 일관성을 유지하기 위한 추가적인 작업이 필요할 수 있습니다.
- 메모리 사용 및 데이터 일관성이 중요한 경우: 데이터셋이 작거나 메모리 사용을 최소화해야 하며, 데이터의 일관성을 유지해야 하는 경우에는 2번 위치(지역)에서 파일을 읽는 것이 좋습니다.
이렇게 말했다 ㅎㅎ..
직접 부하를 주어 테스트를 해보았다.
Mean Time to First Byte는 서버가 클라이언트의 요청을 처리하기 시작한 후 첫 번째 바이트를 클라이언트에게 보내기까지 걸리는 평균 시간을 나타낸다. 낮은 TTFB는 서버가 클라이언트의 요청을 빠르게 처리하고 응답을 보내는 것이기 때문에 사용자의 대기 시간을 줄여 사용자 경험을 향상시킨다.
-local
-global
전역변수로 구현된 코드는 전체적으로 그래프가 낮은 값으로 고르게 분포되어 있다. 하지만 지역변수로 구현된 코드는 순간적으로 TTFB가 90 이상 치솟는 부분을 확인할 수 있다.
결론) 전역변수가 성능에 더 좋다!
- 미션
app.py에서 movieCd, multiMovieYn, repNationCd를 조회하는 기능을 구현했다.
조회된 데이터 중 이렇게 repNationCd가 null 인 데이터가 존재한다. 이 값을 대체하기 위해 영화진흥 위원회의 API 를 호출하여 NULL 값을 채우는 것이 미션이다.
먼저 환경변수로 선언했었던 MOVIE_API_KEY를 사용해 제작국가 데이터가 포함된 영화상세정보 서비스를 사용했다.
def get_key():
"""영화진흥위원회 가입 및 API 키 생성 후 환경변수 선언 필요"""
key = os.getenv('MOVIE_API_KEY')
return key
def gen_url(mcd):
base_url = "http://www.kobis.or.kr/kobisopenapi/webservice/rest/movie/searchMovieInfo.json"
key = get_key()
url = f"{base_url}?key={key}&movieCd={mcd}"
return url
def req(mcd):
url = gen_url(mcd)
print('*'*1000)
print(url)
r = requests.get(url)
code = r.status_code
data = r.json()
return data
@app.get("/movie/{movie_cd}")
def movie_meta(movie_cd: str):
#disk io 발생
#df = pd.read_parquet('/home/sujin/code/ffapi/data')
# df에서 movieCd == movie_cd row를 조회 df[['a']==b] ...
meta_df = df[df['movieCd'] == movie_cd]
if meta_df.empty:
raise HTTPException(status_code=404, detail="영화를 찾을 수 없습니다")
# 조회된 데이터를 .to_dict() 로 만들어 아래에서 return
r = meta_df.iloc[0].to_dict()
if r['repNationCd'] == None:
data = req(r['movieCd'])
#nation = data['movieInfoResult']['movieInfo']['nations']['nationNm']
nations = data["movieInfoResult"]["movieInfo"]["nations"]
nation_names = []
for nation in nations :
nation_names.append(nation['nationNm'])
if '한국' in nation_names:
r['repNationCd'] = 'K'
else:
r['repNationCd'] = 'F'
return r
null 값을 대체하는 코드는 이렇게 작성했다. nation_names를 리스트로 구현한 이유는 제작 국가가 1개가 아닌 여러 국가가 참여한 데이터를 발견했다. 따라서 제작 국가에 한국이 포함되면 K , 아니면 F를 반환하고자 했다.
결과
- Spark Standalone Mode - 클러스터 만들기
* 자바 버전 17로 변경해주기
- Spark를 클러스터 환경에서 실행하여 여러 노드에서 작업을 분산 처리하는 방법
-클러스터란? 여러 대의 컴퓨터들이 연결되어 하나의 시스템처럼 동작하는 컴퓨터들의 집합
$ ifconfig
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=6460<TSO4,TSO6,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
ether 80:65:7c:d1:77:f4
inet6 fe80::1ca6:c30b:91ec:7c9d%en0 prefixlen 64 secured scopeid 0xc
inet 192.168.0.5 netmask 0xffffff00 broadcast 192.168.0.255
nd6 options=201<PERFORMNUD,DAD>
media: autoselect
status: active
192.168.0.5 사용
$ cd $SPARK_HOME
$ sbin/start-master.sh -h 192.168.0.5 --webui-port 7942
[localhost:8080]
$ sbin/start-worker.sh spark://192.168.0.5:7077 -c 4 -m 3G
$ vi code/sparksubmit/sample.py
1 from pyspark import SparkConf
2 from pyspark.sql import SparkSession
3 import sys
4
5 DS_NODASH = sys.argv[1]
6
7 spark = SparkSession.builder.appName(f"simpleName-{DS_NODASH}").getOrCreate()
8
9 # TODO
10 print("*" * 1000)
11 print("=" * 1000)
12
13 #
14
15 spark.stop()
$ $SPARK_HOME/bin/spark-submit --master spark://192.168.0.5:7077 sample.py 20150101
- Amazon S3
[설치]
$ cd ~/tmp/down
$ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
$ unzip awscliv2.zip
$ sudo ./aws/install
# sudo ./aws/install 실패했음
# 수동설치해주었다.
$ brew install awscli
[인증]
$ ls ~/.aws
config credentials
$ cat ~/.aws/config
[default]
region=ap-northeast-2
$ cat ~/.aws/credentials
[default]
aws_access_key_id = AKIA2UC3FCKHZULMDN6O
aws_secret_access_key = 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
aws s3 ls s3://samdulmovie/meta
PRE meta-<ID>/
from pyspark import SparkConf
from pyspark.sql import SparkSession
import sys
DS_NODASH = sys.argv[1]
conf = SparkConf()
conf.set("spark.hadoop.fs.s3a.impl", "org.apache.hadoop.fs.s3a.S3AFileSystem")
conf.set("spark.hadoop.fs.s3a.access.key", "AKIA2UC3FCKHZULMDN6O")
conf.set("spark.hadoop.fs.s3a.secret.key", "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")
spark = SparkSession.builder\
.appName(f"simpleName-{DS_NODASH}")\
.config(conf=conf)\
.getOrCreate()
print("*" * 1000)
df = spark.read.parquet('s3a://samdulmovie/meta')
df.printSchema()
df.write.mode('overwrite').parquet('s3a://samdulmovie/meta-sj')
print("=" * 1000)
spark.stop()
-실행
$ $SPARK_HOME/bin/spark-submit --master spark://Playdata.:7077 sample.py 20150101
printSchema가 제대로 작동한것으로 보아 코드가 성공적으로 수행되었음을 알 수 있다.
- EC2
Amazon EC2 (Elastic Compute Cloud)는 Amazon Web Services (AWS)에서 제공하는 가상 서버 서비스입니다. 이 서비스는 클라우드에서 확장 가능하고 유연한 컴퓨팅 용량을 제공합니다. EC2를 사용하면 물리적인 서버를 직접 관리하지 않고도 필요에 따라 서버를 생성하고 관리할 수 있습니다.
[숙제] MOVIE DATA 수집 프로그램 만들기
- v0.2 - 위 참고(2) 의 코드 중 이미 다운 받은 data 는 skip 하도록 코드 추가 완성
- v0.3 - 위 v0.2 에서 다운받아 저장한 영화목록(data.json) 을 연도별로 읽어서 movieCd 를 추출하고 LOOP 돌면서 "영화 상세정보" API 를 조회하여 저장
- v0.4 - 영화사목록 위와 같은 방식으로 받아 저장
- v0.5 - 영화사 상세정보 위와 같은 방식으로 받아 저장
- v0.6 - 영화인목록 위와 같은 방식으로 받아 저장
- v0.7 - 영화인 상세정보 위와 같은 방식으로 받아 저장
기본 코드는 아래와 같다.
import requests
import os
import json
import time
from tqdm import tqdm
API_KEY = os.getenv('MOVIE_API_KEY')
def save_json(data, file_path):
# 파일저장 경로 MKDIR
os.makedirs(os.path.dirname(file_path), exist_ok=True)
with open(file_path, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=4, ensure_ascii=False)
def req(url):
r = requests.get(url)
j = r.json()
return j
def save_movies(year, per_page=10, sleep_time=1):
file_path = f'data/movies/year={year}/data.json'
# 위 경로가 있으면 API 호출을 멈추고 프로그램 종료
# totCnt 갖여오고 total_pages 계산
url_base = f"https://kobis.or.kr/kobisopenapi/webservice/rest/movie/searchMovieList.json?key={API_KEY}&openStartDt={year}&openEndDt={year}"
r = req(url_base + "&curPage=1")
tot_cnt = r['movieListResult']['totCnt']
total_pages = (tot_cnt // per_page) + 1
# total_pages 만큼 Loop 돌면서 API 호출
all_data = []
for page in tqdm(range(1, total_pages + 1)):
time.sleep(sleep_time)
r = req(url_base + f"&curPage={page}")
d = r['movieListResult']['movieList']
all_data.extend(d)
save_json(all_data, file_path)
return True
하나하나씩 해보았음.
먼저 기본 코드로 2015년에 대한 수행 결과
지정 경로에 2015년 아래 data.json이 생성되었다. 이후 첫 번째 미션 수행
1) 이미 다운 받은 data 는 skip 하도록 코드 추가 완성
# 위 경로가 있으면 API 호출을 멈추고 프로그램 종료
if os.path.exists(file_path):
print(f"데이터가 이미 존재합니다: {file_path}")
return True
테스트코드는 이렇게 작성하였다.
from movdata.ml import save_movies
def test_save_movies():
for y in range(2015,2022):
r = save_movies(year=y, sleep_time=0.1)
assert r
테스트 결과
기본 코드 작성 결과 생성된 2015년 데이터는 skip되고 나머지 2016~2021년 데이터를 수집했다.
또 다시 실행해보면 이렇게 됨.
2) v0.3 - 위 v0.2 에서 다운받아 저장한 영화목록(data.json) 을 연도별로 읽어서 movieCd 를 추출하고 LOOP 돌면서 "영화 상세정보" API 를 조회하여 저장
$ vi movieinfo.py
import requests
import os
import json
import time
from tqdm import tqdm
API_KEY = os.getenv("MOVIE_API_KEY")
def save_json(year,all_data):
file_path = f'data/movies/year={year}/movieinfo.json'
#파일저장 경로 MKDIR
os.makedirs(os.path.dirname(file_path), exist_ok=True)
with open(file_path, 'w', encoding='utf-8') as f:
json.dump(all_data, f, indent=4, ensure_ascii=False)
def req(url):
r = requests.get(url)
j = r.json()
return j
def save_data(year,movie_codes,sleep_time=0.1):
#file_path = f'data/movies/year={year}/movieinfo.json'
url_base = f'http://www.kobis.or.kr/kobisopenapi/webservice/rest/movie/searchMovieInfo.json?key={API_KEY}'
all_data = []
for code in tqdm(movie_codes):
time.sleep(sleep_time)
r = req(url_base + f"&movieCd={code}")
d = r['movieInfoResult']['movieInfo']
all_data.append(d)
save_json(year,all_data)
return True
def load_json(year):
file_path = f'data/movies/year={year}/data.json'
with open(file_path, 'r', encoding='utf-8') as f:
data = json.load(f)
movie_codes = [movie['movieCd'] for movie in data]
save_data(year,movie_codes)
return movie_codes
여기서부터는 모든 년도에 대하여 테스트하지 않고 2015년에 대해서만 수행했다.
load_json은 data.json으로 저장된 영화목록 데이터에서 movieCd를 추출하여 리스트로 저장하는 부분이다.
나는 2015년에 대해서만 수행했으니, 2015년 영화목록에 있는 영화코드가 모두 리스트에 추가될 것 이다.
년도와 영화코드 리스트를 파라미터로 하여 save_data 호출
save_data는 영화상세정보 API를 호출하는 부분이다. 2015년 영화들에 대한 상세정보가 모두 저장될 것 이다.
처음에 all_data.extend(d)라고 작성했다. 이렇게 하니까 all_data에 딕셔너리의 키 값만 저장이 되었다.
extend()는 리스트에 리스트이 요소를 추가하는 것 이고, 딕셔너리에 대해 사용할 경우 키와 값이 아닌 딕셔너리의 키만 추가되기 때문에 적절하지 않은 사용이었다. all_data.append(d)로 수정하였다.
- append(): 전체 딕셔너리를 하나의 항목으로 리스트에 추가.
- extend(): 딕셔너리의 모든 값을 리스트에 개별 항목으로 추가.
save_json에서는 save_data에서 저장한 all_data를 json형식으로 변환하여 지정 경로에 저장한다.
[결과]
3) v0.4 - 영화사목록 위와 같은 방식으로 받아 저장
import requests
import os
import json
import time
from tqdm import tqdm
API_KEY = os.getenv("MOVIE_API_KEY")
def save_json(data, file_path):
# 파일저장 경로 MKDIR
os.makedirs(os.path.dirname(file_path), exist_ok=True)
with open(file_path, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=4, ensure_ascii=False)
def req(url):
r = requests.get(url)
j = r.json()
return j
def save_company(year,company_list,sleep_time):
file_path = f'data/movies/year={year}/company.json'
# 위 경로가 있으면 API 호출을 멈추고 프로그램 종료
if os.path.exists(file_path):
print(f"데이터가 이미 존재합니다: {file_path}")
return True
# 토탈카운트 가져오고 total_pages 계산
url_base = f"http://kobis.or.kr/kobisopenapi/webservice/rest/company/searchCompanyList.json?key={API_KEY}"
all_data=[]
for c in tqdm(company_list):
time.sleep(sleep_time)
r = req(url_base + f"&companyNm={c}")
d = r['companyListResult']['companyList']
all_data.extend(d)
save_json(all_data, file_path)
return all_data
def load_json(year):
file_path = f'data/movies/year={year}/data.json'
with open(file_path, 'r', encoding='utf-8') as f:
data = json.load(f)
company_list = []
for movie in data:
for company in movie['companys']:
company_list.append(company['companyNm'])
save_company(year,company_list,0.1)
return company_list
이번에는 data.json에서 company 데이터를 가져와서 (load_json) 사용했다.
movieCd는 하나인 반면 company 데이터는 한 영화에 여러 제작사가 참여하는 경우도 있었기 때문에
이런식으로 리스트로 구성되어 있어서, 이중 for문을 통해 companyNm을 리스트로 저장하고 영화사 목록 API를 호출하여 데이터를 저장할 수 있었다. 같은 경로에 company.json으로 저장했다.
4) v0.5 - 영화사 상세정보 위와 같은 방식으로 받아 저장
import requests
import os
import json
import time
from tqdm import tqdm
API_KEY = os.getenv("MOVIE_API_KEY")
def save_json(year,all_data):
file_path = f'data/movies/year={year}/companyinfo.json'
#파일저장 경로 MKDIR
os.makedirs(os.path.dirname(file_path), exist_ok=True)
with open(file_path, 'w', encoding='utf-8') as f:
json.dump(all_data, f, indent=4, ensure_ascii=False)
def req(url):
r = requests.get(url)
j = r.json()
return j
def save_data(year,cd_list):
url_base = f'http://www.kobis.or.kr/kobisopenapi/webservice/rest/company/searchCompanyInfo.json?key={API_KEY}'
all_data = []
for code in tqdm(cd_list):
time.sleep(0.1)
r = req(url_base + f"&companyCd={code}")
d = r['companyInfoResult']['companyInfo']
all_data.append(d)
save_json(year,all_data)
return all_data
def load_json(year):
file_path = f'data/movies/year={year}/company.json'
with open(file_path, 'r', encoding='utf-8') as f:
data = json.load(f)
cd_list = [company['companyCd'] for company in data]
save_data(year,cd_list)
return cd_list
movieinfo 코드와 거의 동일하다.
company.json에서 compynyCd를 추출하여 리스트로 저장하고 companyCd를 사용해 영화사 상세정보 API를 호출하여 companyinfo.json 파일을 생성하였다.
여기까지의 결과
5) v0.6 - 영화인목록 위와 같은 방식으로 받아 저장
import requests
import os
import json
import time
from tqdm import tqdm
API_KEY = os.getenv("MOVIE_API_KEY")
def save_json(year,all_data):
file_path = f'data/movies/year={year}/people.json'
#ÆÄÀÏÀúÀå °æ·Î MKDIR
os.makedirs(os.path.dirname(file_path), exist_ok=True)
with open(file_path, 'w', encoding='utf-8') as f:
json.dump(all_data, f, indent=4, ensure_ascii=False)
def req(url):
r = requests.get(url)
j = r.json()
return j
def save_data(year,actor_list):
url_base = f'http://kobis.or.kr/kobisopenapi/webservice/rest/people/searchPeopleList.json?key={API_KEY}'
all_data = []
for actor in tqdm(actor_list):
time.sleep(0.1)
r = req(url_base + f"&peopleNm={actor}")
d = r['peopleListResult']['peopleList']
all_data.extend(d)
save_json(year,all_data)
return all_data
def load_json(year):
file_path = f'data/movies/year={year}/movieinfo.json'
with open(file_path, 'r', encoding='utf-8') as f:
data = json.load(f)
actor_list=[]
for movie in data:
for actor in movie['actors']:
actor_list.append(actor['peopleNm'])
save_data(year,actor_list)
return actor_list
2015년 영화에 출연한 배우들의 데이터를 저장하는 부분이다.
영화인은 동명이인이 있을 수 있기 때문에 영화사 목록을 이중 for문으로 작성한 것과 같은 방식으로 처리해주었다.
여기서부터는 일일 API 호출량을 초과하여 데이터를 저장하지 못했다...!
아쉬운대로 김무열, 표지훈 배우로 테스트한 결과라도...
결과를 보면 이름이 김무열인 사람은 2명이 있다. 배우 김무열님과 제작팀 김무열님이 있다. 영화인 목록에는 배우만 있는 게 아닌가보다
표지훈도 2명이 있다. 배우 표지훈과 기타(?) 표지훈님이 존재
나는 이런 데이터가 역시 재밌다..
[{'filmoNames': '범죄도시4|정직한 후보2|보이스|대외비|침입자|정직한 후보|악인전|인랑|기억의 밤|대립군|머니백|연평해전|개들의 전쟁|은교|최종병기 활 감독확장판|최종병기 활|로맨틱 헤븐|김종욱 찾기|작전|메모리즈|멸공의 횃불|데이 드리밍|인류멸망 보고서',
'peopleCd': '10004099',
'peopleNm': '김무열',
'peopleNmEn': 'GIM Mu-yeol',
'repRoleNm': '배우'},
{'filmoNames': '우상',
'peopleCd': '20337217',
'peopleNm': '김무열',
'peopleNmEn': '',
'repRoleNm': '제작팀'},
{'filmoNames': '뉴 노멀',
'peopleCd': '20389527',
'peopleNm': '표지훈',
'peopleNmEn': '',
'repRoleNm': '배우'},
{'filmoNames': '톱스타',
'peopleCd': '20187083',
'peopleNm': '표지훈',
'peopleNmEn': '',
'repRoleNm': '기타'}]
6) 영화인 상세정보 위와 같은 방식으로 받아 저장
이 부분은 내일 또 API를 호출할 수 있을 때 5번 결과를 다시 저장하여 수행하도록 하겠다 ~!!
🩷 좋았던 점
금요일 휴가 ^__^
숙제(거의)완성했다
숙제하면서 저번 주 배웠었던 내용 복습하며 더 잘 이해할 수 있었다!
내가 관심있는 영화 데이터에 대해서 여러가지 해 볼 수 있어서 좋았다!
저저번주에 완성 못했었던 실습도 이번 주 쉬는 날을 통해서 완성했다!
🥹 아쉬웠던 점
숙제 완벽하게 못 끝냈다! -> 내일 완성할 수 있을 것 같다.
쉬는 날 수업내용 따로 해보려고 했는데 숙제하느라 아직 시도 못했다.
아마존 통해서 하는 내용들은 아직 뭐 하는 건지 잘 모르겠다. 나는 워커 실행, 앱 실행 정도만 할 수 있는듯..(?) 이걸로 뭐 하는건지 더 알려주셨으면 좋겠다.
💪 이 상태에서 다음 일주일을 더 잘 보내려면 어떻게 해야 할까?
수업 내용 필기 열심히해서 마치고 집 왔을 때 필기 보고 다시 똑같이 따라할 수 있도록 하기

'playdata > weekly' 카테고리의 다른 글
[플레이데이터 데이터 엔지니어링 캠프 32기] 8주차 회고 (3) | 2024.09.01 |
---|---|
[플레이데이터 데이터 엔지니어링 캠프 32기] 7주차 회고 (1) | 2024.08.24 |
[플레이데이터 데이터 엔지니어링 캠프 32기] 5주차 회고 (1) | 2024.08.12 |
[플레이데이터 데이터 엔지니어링 캠프 32기] 4주차 회고 (1) | 2024.08.04 |
[플레이데이터 데이터 엔지니어링 캠프 32기] 3주차 회고 (0) | 2024.07.30 |