//////
Search

Java로 대용량 데이터 분석하기 프로젝트 by 이연재

태그
2022/10/11 06:59
사람
최종 편집 일시
2022/10/11 07:03

1. 학습 목표

대용량 데이터 500MB를 읽을 수 있다. 읽어온 데이터를 메모리에 올릴 수 있다. 읽어온 데이터로 데이터 분석을 할 수 있다.

2. 실습 목표

Mdis에서 받은 인구 이동 데이터로 2021 서울에서 가장 많이 이사 간 지역은 어디인지 알아내기

3. 구현

1. 분석할 데이터

1) 분석할 데이터? 2021_인구관련연간자료_20220927_66125.csv
2) 메타 데이터? 데이터들의 정보를 담고 있다. (인덱스, 각 value의 설명 등등)
ex) 인구관련연간자료의 메타 데이터
3) csv란?
Comma Separated Values
쉼표로 구분된 값 파일이다.
파일로 되어있는 데이터를 한줄 씩 읽어서 메모리에 로드해 사용한다. (csv -> java object로)

2. 데이터 처리하는 여러가지 방법

1) Map사용
Map에 <"전입,전출",횟수> 이런 식으로 데이터를 처리할 수 있다.
2) Set사용
중복을 허용하지 않는 Set을 사용해 지역을 카운트하는 방법으로 처리할 수도 있다.
3) Array사용
arr1, arr2를 만들어서 전입 전출을 저장한 다음에 카운트를 할 수도 있다.
위의 세가지 방법말고도 다양한 방법들이 있을 수 있다.

3. 코드 작성

0) 주의 사항
설계하면서 코드 작성할 것!
1.
논리적 설계 - 기능이 어떤것인지 써보는 것
2.
물리적 설계 - java로 코딩하면 어떤 모양이 될 지 써보는 것
3.
구현 - 설계해둔것으로 코딩
메소드 이름 짓기
1.
단일 책임의 원칙 지키기: 메서드는 한 개의 기능만 작동할 수 있도록 작성해야 한다.
2.
어떤 기능을 하는지 알 수 있도록 지어야 한다.(이름이 길어져도 ok, 어차피 컴파일 할 때 빠르게 읽을 수 있도록 알아서 변환한다.)
디버깅 하는 법
1.
상단 플레이버튼 오른쪽 디버그 버튼을 눌러서 디버깅 모드로 실행한다.
2.
에러가 나는 부분에 어떤 값이 들어오는지 확인한다.
1) 파일 읽기
PopulationMove 클래스
PopulationStatistics 클래스
readByChar() 메소드
FileReader를 사용해서 파일 불러오는 메소드
char c = fileReader.read()가 오류 나는 이유?
read()에 ctrl+좌클릭 해보면 int형으로 반환시키는 것을 알 수 있다.
char로 형변환을 해주면 된다.
fileReader로 작성했을 때 엄청 느릴 줄 알았는데 안 느린 이유?
실행하는 부분만 조금 불러오기 때문이다.(선언을 했을 때 파일을 읽는게 아님)
백만 글자 출력해보기
엄청 느리다(모래를 한알 씩 옮기는 것과 같다.) -> 삽으로 옮기자(BufferedReader 쓰자)
메소드가 점점 많아지면 클래스로 나눠야 한다.
파일 별로 클래스나 interface나눠서하기, 한 파일에 interface, class등등 다 넣으면 보긴편하지만 협업을 할 땐 어디에 무슨 클래스가 있는지 찾을 수가 없다.
readByLine() 메소드
BufferedReader를 사용해서 파일 불러오는 메소드
readLine을 사용하면 한 줄씩 불러올 수 있다.
데이터가 커서 불러오는데 몇 초걸리긴 하지만 fileReader보다는 빠르다.
readByLine2() 메소드
Files.newBufferedReader를 사용해서 파일 불러오는 메소드
요즘 많이 사용하는 스타일이다.
그냥 BufferedReader랑 속도는 비슷하다.
2) parse 구현
parse 메소드
parsing이란?
주어진 데이터를 내가 원하는 형태로 가공해서 사용하는 것이다.
parse()메소드
전입, 전출 코드를 parsing하는 메소드이다.
split(): String[] 타입으로 리턴하는 메소드, ()안의 구분자로 잘라서 배열에 넣어준다.
ex)
3) readByLine 수정
readByLine 메소드
main 메소드
readByLine()메소드 수정
while문 안에서 string을 populationMove로 parsing하여 pml에 add한다.
루프가 끝나면(파일을 모두 읽어서 parsing을 끝냈으면) return한다.
500mb를 매번 읽는 것은 부담이다.
왜? 한번 파일을 메모리로 로드 하는데 10초 가량 걸리기 때문이다.
따라서 필요한 부분만 파일로 저장해서 사용하면 좋다.(위의 코드에선 전입 전출만 뽑아서 저장)
4) 파일 생성
createAFile 메소드
main 메소드
createAFile()메소드
createNewFile를 이용해서 from_to.txt파일을 생성한다
5) 파일 쓰기
write 메소드
fromToString 메소드
main 메소드
write()메소드
List를 지정한 파일에 write하는 메소드이다.
write를 이용해 fromToString으로 가공된 데이터를 from_to.txt에 저장한다.
fromToString()메소드
전입,전출 코드를 저장할 때 콤마(,)로 구분해서 가공해주는 메소드이다.
6) parse 수정
parse 메소드
main 메소드
parse()메소드 수정
전입, 전출 코드만 담겨있는 from_to.txt을 불러와서 사용하기 때문에 인덱스를 0과 1로 바꾼다.
7) count후 저장
getMoveCntMap 메소드
main 메소드
getMoveCntMap()메소드
HashMap을 생성해 <“전입,전출”, cnt>의 형식으로 moveCntMap에 저장하는 메소드
1.
List<PopulationMove>를 순환 하면서 "전입,전출" 형태의 key를 만든다.
2.
moveCntMap에서 해당 key에 해당하는 Object가 없으면 생성하고 1이라고 check한다.
3.
key로 꺼내서 +1한다.
4.
moveCntMap을 return한다.
getMoveCntMap()메소드에서 return된 moveCntMap을 each_sido_cnt.txt에 저장한다.
8) 히트맵 그리기
heatmapIdxMap 메소드
main 메소드
heatmapIdxMap()메소드
각 시도코드를 map에 저장하는 메소드
for_heatmap.txt에 [x의 index, y의 index, conut], 형식으로 write한다.
결과

4. 추가로 생각해볼 것들

객체지향적으로 리펙토링 해보기