빅데이터/하둡

하둡 1.0 튜토리얼 - (9) 항공 데이터 분석 1

_금융덕후_ 2019. 7. 15. 00:21
728x90
반응형

 

데이터 준비

데이터 설명

이번에는 맵리듀스를 사용해 실제 데이터 분석을 해보려 합니다.

먼저 다음 사이트에서 데이터를 다운받아야 합니다.

http://stat-computing.org/dataexpo/2009/the-data.html 

 

위의 링크의 데이터는 미국 내 모든 항공편에 대한 도착과 출발에 대한 세부 정보들을 담은 데이터입니다.

년, 월, 등 시간 및 항공사 정보, 출발시간, 도착시간, 출발지, 도착지 등에 대한 데이터가 들어있습니다.

 

데이터 다운로드

위의 링크로 들어가면 년도별로 데이터를 다운받을 수 있지만,

Shell Script를 사용해 한번에 데이터를 내려받고, 수정하도록 하겠습니다.

수정 내용은, 첫줄의 컬럼정보를 없애는 작업입니다.

#!/bin/bash

for ((i=1987; i <= 2008; i++)) ; do
  wget http://stat-computing.org/dataexpo/2009/$i.csv.bz2
  bzip2 -d $i.csv.bz2
  sed -e '1d' $i.csv > $i_temp.csv
  mv $i_temp.csv $i.csv
done

위의 Shell Script는 어떠한 OS에서 사용하느냐에 따라 동작하지 않을 수 있습니다. (Ubunut기준입니다.)

CentOS는 첫줄을 #! /bin/bash로 고치시면 되고,

윈도우가 호스트이고 Python 3.x가 깔려있다면 다음 코드를 사용하시면 될것같습니다.

import urllib.request as request
import bz2
import os

for i in range(1987, 2009):
	url = "http://stat-computing.org/dataexpo/2009/{}.csv.bz2".format(i)
	out_fname = "./{}.csv.bz2".format(i)
	final_fname = "./{}.csv".format(i)
	request.urlretrieve(url, out_fname)
	print("downloaded file: {}".format(out_fname))
	with bz2.open(out_fname, "rb") as in_file, open(final_fname, "w") as out_file:
		data = in_file.read().decode('utf-8').split('\n')[1:]
		data = "\n".join(data)
		out_file.write(data)
	print("wrote file: {}".format(final_fname))

for item in os.listdir('./'):
	if item.endswith('.bz2'):
		os.remove(os.path.join('./', item))

 

다운로드를 받으신 뒤 다음 리눅스 명령어를 입력하시면 해당 폴더가 차지하는 데이터 양을 볼 수 있습니다.

> du -s -h .

데이터는 약 12G정도 되는 것 같습니다.

(혹시라도 각 VM의 사이즈를 20기가 밑으로 잡으신 분들은 하둡으로 업로드가 힘드실테니 각각 업로드 후 하둡에 집어넣으셔야 할 것 같습니다.)

 

파일 옮기기

이제 scp를 이용해 doop01로 파일을 옮겨주겠습니다.

> scp -rp . doop@doop01:~/

 

그리고 하둡파일시스템으로 csv파일을 넣어줍니다.

VM의 용량을 20기가 이상으로 잡으셨다면 상관 없겠지만,

혹시 모를 염려가 생겨 하나씩 hdfs에 복사하고 namenode 기기 즉 doop01의 로컬에 있는 파일을 지우는 Shell Script를 작성했습니다.

#!/bin/sh

./hadoop/bin/hadoop dfs -mkdir input
for ((i=1987; i <= 2008; i++)) ; do
  ./hadoop/bin/hadoop dfs -put ~/$i.csv input
  rm -rf $i.csv
done

 

혹시라도 신경을 안쓰시거나 각 VM을 20기가 이상 잡으셨다면 다음 커맨드를 사용하시기 바랍니다.

> hadoop dfs -mkdir input
> hadoop dfs -put ~/doop/*.csv input

참고로 dfs는 fs와 동일한 기능을 합니다.

 

전송 결과 확인

파일을 HDFS로 옮기는 것이 끝났다면 마지막으로 확인을 해주겠습니다.

> hadoop dfs -ls

다음과 같은 로그가 나올 것입니다.

Found 22 items
-rw-r--r--   3 doop supergroup  127162642 2019-07-14 11:05 /user/doop/input/1987.csv
-rw-r--r--   3 doop supergroup  501039172 2019-07-14 11:05 /user/doop/input/1988.csv
-rw-r--r--   3 doop supergroup  486518521 2019-07-14 11:05 /user/doop/input/1989.csv
-rw-r--r--   3 doop supergroup  509194387 2019-07-14 11:05 /user/doop/input/1990.csv
-rw-r--r--   3 doop supergroup  491209793 2019-07-14 11:05 /user/doop/input/1991.csv
-rw-r--r--   3 doop supergroup  492313431 2019-07-14 11:06 /user/doop/input/1992.csv
-rw-r--r--   3 doop supergroup  490753352 2019-07-14 11:06 /user/doop/input/1993.csv
-rw-r--r--   3 doop supergroup  501558365 2019-07-14 11:06 /user/doop/input/1994.csv
-rw-r--r--   3 doop supergroup  530751268 2019-07-14 11:06 /user/doop/input/1995.csv
-rw-r--r--   3 doop supergroup  533922063 2019-07-14 11:06 /user/doop/input/1996.csv
-rw-r--r--   3 doop supergroup  540347561 2019-07-14 11:06 /user/doop/input/1997.csv
-rw-r--r--   3 doop supergroup  538432575 2019-07-14 11:07 /user/doop/input/1998.csv
-rw-r--r--   3 doop supergroup  552925722 2019-07-14 11:07 /user/doop/input/1999.csv
-rw-r--r--   3 doop supergroup  570151313 2019-07-14 11:07 /user/doop/input/2000.csv
-rw-r--r--   3 doop supergroup  600411162 2019-07-14 11:07 /user/doop/input/2001.csv
-rw-r--r--   3 doop supergroup  530506713 2019-07-14 11:08 /user/doop/input/2002.csv
-rw-r--r--   3 doop supergroup  626744942 2019-07-14 11:08 /user/doop/input/2003.csv
-rw-r--r--   3 doop supergroup  669878813 2019-07-14 11:08 /user/doop/input/2004.csv
-rw-r--r--   3 doop supergroup  671026965 2019-07-14 11:08 /user/doop/input/2005.csv
-rw-r--r--   3 doop supergroup  672067796 2019-07-14 11:09 /user/doop/input/2006.csv
-rw-r--r--   3 doop supergroup  702877893 2019-07-14 11:09 /user/doop/input/2007.csv
-rw-r--r--   3 doop supergroup  689413044 2019-07-14 11:09 /user/doop/input/2008.csv

 

파일이 정확히 들어갔는지 내용을 보고싶다면, 파일을 하나 골라 마지막 내용을 출력해볼 수 있습니다.

> hadoop dfs -tail input/1988.csv

결과는 다음과 같이 나옵니다.

1988,12,7,3,1325,1325,2057,2034,DL,162,NA,332,309,NA,23,0,HNL,LAX,2556,NA,NA,0,NA,0,NA,NA,NA,NA,NA
1988,12,8,4,1325,1325,2042,2034,DL,162,NA,317,309,NA,8,0,HNL,LAX,2556,NA,NA,0,NA,0,NA,NA,NA,NA,NA
1988,12,9,5,1325,1325,2055,2034,DL,162,NA,330,309,NA,21,0,HNL,LAX,2556,NA,NA,0,NA,0,NA,NA,NA,NA,NA
1988,12,10,6,1325,1325,2258,2034,DL,162,NA,453,309,NA,144,0,HNL,LAX,2556,NA,NA,0,NA,0,NA,NA,NA,NA,NA
1988,12,11,7,1325,1325,2051,2034,DL,162,NA,326,309,NA,17,0,HNL,LAX,2556,NA,NA,0,NA,0,NA,NA,NA,NA,NA
1988,12,12,1,1325,1325,2043,2034,DL,162,NA,318,309,NA,9,0,HNL,LAX,2556,NA,NA,0,NA,0,NA,NA,NA,NA,NA
1988,12,13,2,1325,1325,2038,2034,DL,162,NA,313,309,NA,4,0,HNL,LAX,2556,NA,NA,0,NA,0,NA,NA,NA,NA,NA
1988,12,14,3,1325,1325,2045,2034,DL,162,NA,320,309,NA,11,0,HNL,LAX,2556,NA,NA,0,NA,0,NA,NA,NA,NA,NA
1988,12,1,4,2027,2027,2152,2145,DL,163,NA,85,78,NA,7,0,ATL,MCO,403,NA,NA,0,NA,0,NA,NA,NA,NA,NA
1988,12,2,5,2106,2027,2229,2145,DL,163,NA,83,78,NA,44,39,ATL,MCO,403,NA,NA,0,NA,0,NA,NA,NA,NA,NA

 

프로젝트 생성

파일 복사가 끝났다면 이제 프로젝트를 생성해주겠습니다.

IntelliJ를 열어 새 프로젝트를 만들어줍니다. 이름은 airlinedata라고 짓겠습니다.

com > jyoon > study > airlinedata라는 패키지 구조를 만들어주겠습니다.

 

Gradle Dependency

이전 워드카운트 문제와 동일하게 dependency는 다음과같이 두개의 라이브러리를 사용하겠습니다.

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.12'
    implementation 'org.apache.hadoop:hadoop-common:3.1.2'
    implementation 'org.apache.hadoop:hadoop-mapreduce-client-core:3.1.2'
}

 

Parser 클래스

가장 먼저 Parser클래스를 구현할 것입니다. 이 클래스는 위의 항공데이터 중 출발 지연시간과 도착 지연시간을 추출하기 위해 작성합니다. 코드를 작성하기 전에 위의 샘플 데이터의 가장 마지막 한줄의 정보를 테이블로 만들어보겠습니다.

컬럼 이름 운항년도 운항월 항공사코드 도착지연시간 출발지연시간 운항거리
컬럼 인덱스 0 1 8 14 15 18
정보 1988 12 DL 44 39 403

 

아래 코드는 Comma로 split한 뒤 위의 컬럼들만 뽑아내는 역할을 하는 코드입니다.

AirlinePerformanceparser.java라고 이름 짓고 다음 코드를 작성해줍니다.

import org.apache.hadoop.io.Text;

public class AirlinePerformanceParser {
    private int year;
    private int month;

    private int arrivalDelayTime = 0;
    private int departureDelayTime = 0;
    private int distance = 0;

    private boolean arrivalDelayAvailable = true;
    private boolean departureDelayAvailable = true;
    private boolean distanceAvailable = true;

    private String uniqueCarrier;

    public AirlinePerformanceParser(Text text){
        
        try {
            // 한 row를 comma로 split 한다
            String[] columns = text.toString().split(",");
            year = Integer.parseInt(columns[0]); // 운항 년도
            month = Integer.parseInt(columns[1]); // 운항 월
            uniqueCarrier = columns[8]; // 항공사 코드
            if (!columns[15].equals("NA")) // 항공기 출발 지연 시간
                departureDelayTime = Integer.parseInt(columns[15]);
            else
                departureDelayAvailable = false;

            if (!columns[14].equals("NA")) // 항공기 도착 지연 시간
                arrivalDelayTime = Integer.parseInt(columns[14]);
            else
                arrivalDelayAvailable = false;

            if (!columns[18].equals("NA")) // 운항 거리
                distance = Integer.parseInt(columns[18]);
            else
                distanceAvailable = false;
        } catch (Exception ex){
            System.out.println("Error parsing a record: " + ex.getMessage());
        }

    }
}

 

위 코드를 작성한 뒤 IntelliJ에서 member변수 중 하나에 오른쪽 클릭을 하고, Generate을 클릭해줍니다.

 

이후 뜨는 팝업 창에서 Getter를 선택하고,

 

모든 변수들을 다 선택해준 뒤 OK를 누르면 Getter함수들을 자동으로 생성하게 됩니다.

 

다음 포스팅에서는 맵리듀스로 해당 데이터를 조회하고 분석해보겠습니다.

 

참고자료

이 포스팅은 "시작하세요! 하둡 프로그래밍" 책의 예제를 무작정 따라해본 포스팅입니다.

https://wikibook.co.kr/beginning-hadoop-programming-2rev/

728x90
반응형