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

허진혁·2022년 10월 9일
0

목표

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

파일 정보 및 정리

  • Mdis에서 받은 인구이동 데이터 (인구 > 국내인구이동통계 > 인구관련연간자료 > 2021) mdis

전입행정시구역코드 : 1
전출행정시구역코드 : 2

  • 도시 코드

파일경로 찾기(mac)

  • cmd + opt + c

메서드 설계 주의사항

  • 하나의 메서드에는 하나의 책임을 진다
  • 메서드명은 나중에 볼 때도 알 수 있게 작명 해야한다

프로젝트 파일

PopulationMove

전입, 전출 클래스

import java.util.HashMap;
import java.util.Map;

public class PopulationMove {
    private int toSido; // 전입
    private int fromSido; // 전출

    static Map<Integer, String> sidoMap = new HashMap<>();

   
   // int 데이터를 받을 때 생성자		
    public PopulationMove(int toSido, int fromSido) {
        this.toSido = toSido;
        this.fromSido = fromSido;
    }
   // String 데이터를 받을 때 int 타입으로 변환한 생성자
    public PopulationMove(String toSido, String fromSido) {
        this.toSido = Integer.parseInt(toSido);
        this.fromSido = Integer.parseInt(fromSido);
    }

    public int getFromSido() {
        return fromSido;
    }

    public int getToSido() {
        return toSido;
    }

}

PopulationStatistics

인구통계 파일다루는 클래스

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class PopulationStatistics {
    // 한 바이트씩 읽는 메서드 (100만글자까지)
    public void readByChar(String fileName) throws IOException {
        FileReader reader = new FileReader(fileName);
        String fileContents = "";
        while (fileContents.length() < 1000000) {
            char ch = (char) reader.read();
            fileContents += ch;
        }
        reader.close();
    }

   // 파일을 한 줄씩 읽어 파일의 모든 내용을 읽는 메서드
    public List<PopulationMove> readByLine(String fileName) throws IOException{
        List<PopulationMove> pml = new ArrayList<>();
        BufferedReader reader = new BufferedReader(new FileReader(fileName));
        String fileContents = "";

			//while문 안에서 string을 PopulationMove로 파싱하여 pml에 추가
		    //루프가 끝나면 return 합니다.
        while ((fileContents = reader.readLine()) != null) {
				//  System.out.println(fileContents);
            PopulationMove pm = parse(fileContents);
            pml.add(pm);
        }
        reader.close();
        return pml;
    }

    // 에러를 try catch
    public void readByLineV2(String fileName) {
        try (BufferedReader reader = Files.newBufferedReader(Paths.get(fileName),
                StandardCharsets.UTF_8)) {
            String fileContents;
            while ((fileContents=reader.readLine()) != null) {
                System.out.println(fileContents);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    // PopulationMove 파싱 메서드 1 : 첫 파일의 데이터 중 전입(arr[0])과 전출(arr[6]) 추출
    public PopulationMove parseV1(String data) {
        String[] arr = data.split(",");
        return new PopulationMove(arr[0], arr[6]);
    }

    // PopulationMove 파싱 메서드 2 : 데이터를 추출한 파일의 전입(arr[0])과 전출(arr[1]) 추출
    public PopulationMove parseV2(String data) {
        String[] arr = data.split(",");
        return new PopulationMove(arr[0], arr[1]);
    }

    // 필요한 데이터만 추출하기 위한 새 파일 만들기
    public void createAFile(String fileName) {
        File file = new File(fileName);
        try {
            file.createNewFile();
        } catch (IOException e) {
            throw new RuntimeException();
        }
    }

		// 새 파일에 내용 추가 후 파일이름 저장
    public void write(List<String> strs, String fileName) throws IOException{
        File file = new File(fileName);

        BufferedWriter writer = new BufferedWriter(new FileWriter(file));
        for (String str : strs) {
            writer.write(str);
        }
        writer.close();
    }

    // PopulationMove 객체 안에 데이터들을 String으로 변환
    public String fromToString(PopulationMove populationMove) {
        return populationMove.getFromSido() + "," + populationMove.getFromSido() + "\n";
				}
	
    // 도시 이동에 대한 각각의 개수 찾기
    public Map<String, Integer> getMoveCntMap(List<PopulationMove> pml) {
        Map<String, Integer> moveCntMap = new HashMap<>();
        for (PopulationMove pm : pml) {
            String key = pm.getToSido() + "," + pm.getFromSido();
            // key에 해당하는 값이 없다면 디폴트 값을 0으로 지정, 키가 중복된다면 값 +1 반복
            if (moveCntMap.get(key) == null) {
                moveCntMap.put(key, 1);
            }
            moveCntMap.put(key, moveCntMap.get(key) + 1);
//            moveCntMap.getOrDefault(key, moveCntMap.getOrDefault(key, 0) + 1);
        }
        return moveCntMap;
    }

Main

실행 목적 클래스

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class Main {
    public static void main(String[] args) throws IOException {
        String address = "/Users/jinhyuck/Downloads/2021_인구관련연간자료_20221007_89221.csv";
        PopulationStatistics populationStatistics = new PopulationStatistics();
        List<PopulationMove> pml = populationStatistics.readByLine(address);

				// 파일을 원하는 데이터로 가공
        List<String> strings = new ArrayList<>();
        for (PopulationMove pm : pml) {
            String fromTo = populationStatistics.fromToString(pm);
            strings.add(fromTo);
//           System.out.printf("전입: %s, 전출: %s \n", pm.getToSido(), pm.getFromSido()); // 확인용
        }
        populationStatistics.write(strings, "./from_to.txt");
				// .from_to.txt 파일 안의 형태 (11,11)

				// 도시 이동에 대한 개수 파악 (형태 --> 44,27=2146)
        Map<String, Integer> moveCntMap = populationStatistics.getMoveCntMap(pml);
        System.out.println(moveCntMap);

        // 새로운 파일에 전입,전출,이동수 를 저장 (형태 --> key:44,27 value:2146)
        String targetFilename = "each_sido_cnt.txt";
        populationStatistics.createAFile(targetFilename);
        List<String> cntResult = new ArrayList<>();
        for (String key : moveCntMap.keySet()) {
            String str = String.format("key:%s value:%d\n", key, moveCntMap.get(key));
            cntResult.add(str);
        }
        populationStatistics.write(cntResult, targetFilename);
profile
Don't ever say it's over if I'm breathing

0개의 댓글