빅데이터/하둡

하둡 1.0 튜토리얼 - (8) 맵리듀스

_금융덕후_ 2019. 7. 14. 17:19
728x90
반응형

 

맵리듀스

하둡에서 파일을 분석하고 조회할때는 맵리듀스라는 기술을 사용합니다.

JobTracker는 각 TaskTracker에서 Map을 수행할 수 있도록 데이터를 분배하고 Map 프로그램을 건네줍니다.

이때 데이터의 입출력은 항상 <Key, Value> 페어로 전달됩니다.

TaskTracker는 Map 프로그램을 수행하고 결과를 자신의 로컬 디스크에 파일로 떨궈줍니다.

하둡 시스템은 TaskTracker들이 Map수행이 모두 끝날때까지 기다렸다가 파일들을 Reduce를 수행할 TaskTracker들에게 전달합니다. 이 작업을 Shuffle/Sort라고 부릅니다.

Reduce를 전달받은 TaskTracker들은 Reduce 프로그램을 수행하고 마지막으로 집계를 한 뒤 최종 파일을 생성합니다.

 

위의 단계들 중 Map과 Reduce를 프로그램이라고 부르는 이유가 있습니다.

개발자가 직접 작성해 주어야 하기 때문입니다.

 

워드카운트 문제

하둡에서 기본적으로 제공하는 예제인 워드카운트 문제를 수행해보겠습니다.

이미지출처: https://www.edureka.co/blog/mapreduce-tutorial/

워드카운트문제는 처음 입력으로 받은 텍스트를 각 Map을 수행하는 TaskTracker에게 나누어 분배합니다.

그리고 각 TaskTracker가 문장을 토큰화한 뒤 각 토큰(단어)에 1을 붙여 리턴합니다.

셔플링이 일어날 때 각 1이 리스트형태로 바뀌게 되고,

리스트의 각 원소를 또 Reduce를 수행하는 TaskTracker가 모두 더해 마지막 출력으로 전달하게 됩니다.


프로젝트 생성

먼저 프로젝트를 생성해주겠습니다. 패키지명은 이전과 동일하고 Artifact는 wordcount라고 이름 짓겠습니다.

 

프로젝트 창이 뜨면 하단에 다음과같이 Gradle에 필요한 파일들을 다운로드 받기 시작합니다.

이 작업이 끝날때까지 기다려줍니다.

 

패키지 생성

패키지 구성은 src > main > java > com > jyoon > study > wordcount가 되겠습니다.

 

Gradle Dependency

Gradle에는 지난번과는 다르게 하나의 패키지를 더 내려받습니다.

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'
}

이번에는 mapreduce에 관련된 라이브러리를 함께 받게됩니다.

 

Mapper 클래스

이제 Mapper클래스를 작성해주겠습니다.

 

wordcount폴더에서 오른쪽 마우스 클릭을 해주고 New > Java Class를 클릭합니다.

그리고 클래스 이름란에 WordCountMapper라고 작성하고 OK를 클릭해줍니다.

 

그리고 아래의 코드를 작성해줍니다.

 

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;
import java.util.StringTokenizer;

public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
    private final static IntWritable one = new IntWritable(1);
    private Text word = new Text();
    
    public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        StringTokenizer itr = new StringTokenizer(value.toString());
        while (itr.hasMoreTokens()){
            word.set(itr.nextToken());
            context.write(word, one);
        }
    }
}​

코드를 보면 WrodCountMapper는 하둡에서 제공하는 Mapper클래스를 상속받습니다.

Mapper클래스 오른쪽으 제네릭은 차례로 입력키, 입력값, 출력키, 출력값 입니다.

map함수 하나가 작성되어 있습니다. 이 함수는 Mapper클래스를 상속받아 메소드를 재정의하는 것입니다.

Text를 받아 그것을 토큰화 하고 각 토큰과 함께 숫자 1을 Context에 쓰기 해주는 코드입니다.

Context에 쓰고 나면 하둡이 알아서 TaskTracker의 로컬디스크에 파일을 작성하게 되고, 셔플/소팅이 일어납니다.

 

Reducer 클래스

Mapper를 생성해줄 때와 같이 wordcount폴더에 WordCountReducer.java 파일을 생성해주고 아래 코드를 작성합니다.

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;


import java.io.IOException;

public class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
    private IntWritable result = new IntWritable();

    public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
        int sum = 0;
        for (IntWritable val : values)
            sum += val.get();
        result.set(sum);
        context.write(key, result);
    }
}

리듀서 클래스는 reduce라는 함수를 재정의합니다.

위에서 언급한 바와 같이 Iterable즉 일종의 리스트 형태의 값들을 받아 모두 더한 뒤 context에 쓰이게 하는 형태입니다.

 

Driver 클래스

마지막으로 위의 Map과 Reduce 태스크를 하둡이 실행할 수 있게 해주는 Driver클래스를 작성합니다.

역시 wordcount폴더 안에 WordCount.java라는 파일을 생성하고 아래 코드를 작성해줍니다.

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;

public class WordCount {
    public static void main(String[] args) throws Exception{
        Configuration conf = new Configuration();
        if (args.length != 2){
            System.err.println("Usage: WordCount <input> <output>");
            System.exit(2);
        }
        
        // Deprecate Warning hadoop-mapreduce-client-core 버전3이상은 안씀 (무시해도 됨)
        Job job = new Job(conf, "WordClass");
        
        job.setJarByClass(WordCount.class);
        job.setMapperClass(WordCountMapper.class);
        job.setReducerClass(WordCountReducer.class);
        
        job.setInputFormatClass(TextInputFormat.class);
        job.setOutputFormatClass(TextOutputFormat.class);
        
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);
        
        FileInputFormat.addInputPath(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));
        
        job.waitForCompletion(true);
    }
}

위의 파일은 main함수 하나만 가지고 있습니다. 이 main함수를 통해 Map과 Reduce가 실행됩니다.

main의 첫 if문을 보면 command line input을 체크하고 있습니다.

해당 jar파일을 실행할 때 argument가 두개가 없으면 프로그램을 종료하는 코드입니다.

 

WordCount 실행

이제 워드카운트를 실행해보도록 하겠습니다.

 

jar Build

먼저 IntelliJ에서 해당 프로젝트를 jar로 빌드해야합니다.

왼쪽 상단의 메뉴에서 File > Project Structure를 클릭해 Jar Build를 셋팅하고, Jar build를 실행합니다.

(자세한 가이드는 이전 포스팅에 나와있습니다.)

 

빌드된 파일은 프로젝트 폴더 내의 out > artifacts > wordcouunt_jar 폴더에 생성되게 됩니다.

이제 이 jar 파일을 하둡에서 실행시켜야 합니다.

 

다음 커맨드를 입력해 jar파일을 doop01기기로 옮겨줍니다. (저는 먼저 jar파일을 Downloads폴더에 옮겨주었습니다.)

> scp wordcount.jar doop@doop01:~/

 

먼저 doop01기기로 돌아가서 단어를 새어줄 파일을 생성합니다. input.txt라고 이름 짓겠습니다.

read a book
write a book

 

그리고 hdfs명령을 이용해 input.txt파일을 hdfs로 집어넣어줍니다.

> hadoop fs -put input.txt input.txt

(그리고 ls명령으로 파일이 잘 들어갔는지 확인해주시기 바랍니다.)

 

이제 jar 파일을 실행합니다.

hadoop jar wordcount.jar com.jyoon.study.wordcount.WordCount input.txt wordcount_output

 

실행을 하면 다음과같은 로그를 출력하며 맵리듀스가 실행됩니다.

19/07/14 04:06:38 INFO input.FileInputFormat: Total input paths to process : 1
19/07/14 04:06:38 INFO util.NativeCodeLoader: Loaded the native-hadoop library
19/07/14 04:06:38 WARN snappy.LoadSnappy: Snappy native library not loaded
19/07/14 04:06:38 INFO mapred.JobClient: Running job: job_201907120159_0004
19/07/14 04:06:39 INFO mapred.JobClient:  map 0% reduce 0%
19/07/14 04:10:24 INFO mapred.JobClient:  map 100% reduce 0%
19/07/14 04:10:32 INFO mapred.JobClient:  map 100% reduce 33%
19/07/14 04:10:33 INFO mapred.JobClient:  map 100% reduce 100%
...

 

마지막으로 실행 결과를 확인해보겠습니다. 역시 hdfs명령어를 사용합니다.

> hadoop fs -cat wordcount_output/part-r-00000

 

위의 명령을 실행하면 하둡이 실행 결과로 출력한 파일인 part-r-00000의 내용을 보여주게 됩니다.

a       2
book    2
read    1
write   1

파일의 내용안의 단어들을 잘 세어놓은 것을 확인할 수 있습니다.

 

자세히 설명하지는 않겠지만, 위 결과를 웹인터페이스에서도 확인할 수 있습니다.

웹브라우저를 열어 다음 url로 접속하시면 됩니다. 네임노드 서버는 해당 기기의 ip로 대체하시기 바랍니다.

http://네임노드서버:50030/joptracker.jsp

가장 하단으로 내려가면 해당 job에대한 정보가 나오게됩니다.

 

참고자료

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

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

728x90
반응형