으아. 무려 한시간 동안 쓴 거를 순간 날려먹었다. 다시 쓰자.
Hadoop의 Basic Example을 소개하려고 한다. 당연히 MapReduce를 사용하는 예제를 보여줄 것이고 그것에 대한 가장 기본적인 예제가 WordCount 이다. C에서의 HelloWorld라고 생각하면 된다.
Hadoop의 MapReduce를 수행하기 위해서는 당연히 Mapper Function과 Reducer Function이 필요하다. 그리고 그것을 수행시켜줄 main Function도 당연히 필요하다. 아래는 WordCount Example 예제이다. (Java로 쓰여져있다.)
보다 시피 map function과 reduce function이 있다. 그리고 뭐라고 쓰여있는 것인지는 모르겠지만 main function도 있다. 우리는 우선 main function 부터 알아볼 생각이다. main function에서 하는 일은 크게 아래와 같다.
1. JobConf를 선언한다.
2. JobConf를 통해서 Mapper를 설정한다.
3. JobConf를 통해서 Reducer를 설정한다.
4. JobConf를 통해서 Mapper와 Reducer의 input 그리고 output Type을 설정한다.
5. input과 output의 path 정보를 설정한다. (argument 관련된 정보이다.)
6. JobClient object를 통해서 JobConf object를 실행시킨다. 이 때 사용하는 함수가 runJob이다.
자꾸 JobConf JobConf하는데 JobConf가 무엇이냐? 여행사와 같은 에이전트 역할을 한다고 보면 된다. 우리가 해외여행을 갈 때는 보통 여행사에 Contact을 해서 숙소,일정 등을 잡고 여행사가 현지의 숙소, 비행일정등을 잡아준다. 마찬가지로 우리는 JobConf를 통해서 Hadoop의 MapReduce를 이용할 것이다. 우리는 JobConf에게 위의 1번부터 6번까지의 일을 해줄 것이며 나머지는 JobConf가 알아서 map Function 그리고 reducer Function을 Call 할 것이다.
참고로 더욱 정확한 JobConf의 내용은 아래를 참고하자.
Hadoop 공식 사이트에서 Capture한 것이다.
굳이 위의 1번, 2번,3번, 6번은 설명하지 않겠다. 소스코드를 보면 금방 알 수 있다.
4. JobConf를 통해서 Mapper와 Reducer의 input 그리고 output Type을 설정한다.
Mapper와 Reducer는 당연히 각각의 input Type과 output Type이 있다. 그리고 당연한 이야기 이지만 Mapper의 output이 Reducer의 input으로 가기 때문에 그 두개의 Type은 같아야 한다. 예를 들어, Mapper의 output의 Key/Value output Type이 String/Int이면 Reducer의 Input의 Key/Value input Type 역시 String/Int 이어야 한다.
위의 소스코드를 보면 Text.class, IntWritable.class를 볼 수 있을 것이다. 그 두 개가 각각 String과 Int 형에 대한 Hadoop의 object이다. Hadoop은 String과 Int를 자기 나름데로 Class로 구현하여 사용한다.
JobConf를 통해서 input 그리고 output의 Type을 결정하는 부분은 아래와 같다.
conf.setInputFormat(TextInputFormat.class);
conf.setOutputFormat(TextOutputFormat.class);
conf.setOutputKeyClass(Text.class);
conf.setOutputValueClass(IntWritable.class);
TextInputFormat.class에 대해서 또 이야기 하고 넘어가야 하는 것이 있다. 아래의 표를 보자.
위의 Table이 모두 설명해주고 있으니 굳이 따로 추가적인 설명은 생략하겠다. 표에서 밑에 두 개의 Class는 적어도 한 번 써본 후 설명하려고 한다. 일단은 공백으로 놔두려고 한다.
5. input과 output의 path 정보를 설정한다. (argument 관련된 정보이다.)
FileInputFormat.setInputPaths(conf, new Path(args[0]));
FileOutputFormat.setOutputPath(conf, new Path(args[1]));
이 부분은 input과 output의 argument 위치를 말해주는 부분이다.
위의 그림은 Hadoop 공식 홈페이지에서 캡쳐한 것이니 참고하시길 바란다.
개괄적인 것은 모두 설명했으니 이제 WordCount를 이해해보자.
이 예제는 TextInputFormat.class를 사용하고 있기 때문에 Input의 Key/Value pair는 각각 LongWritable/Text Type을 가지게 된다. WordCount는 말 그대로 단어 세는 프로그램이다. 예를 들어 다음의 txt 파일이 Input으로 들어왔다고 해보자.
========= sample.txt =========
I love you
you do not love me I am sad
=============================
위의 txt 파일은 두 line이 있다. 한 줄 한 줄이 각각 Input이 될 것이다. I love you라는 하나의 Input과 you do not love me I am sad라는 하나의 Input이다. I love you는 TextInputFormat.class에서는 LongWritable Type의 Key와 Text Type의 Value로 구분된다. 이 때 LongWritable은 byte offset이므로 <10, "I love you"> 이렇게 된다. 두 번째 line은 <27, "you do not love me I am sad"> 이렇게 된다.
이 Input으로 map Function을 돌린다. 각각의 value를 스페이스로 구분하여 key로 놓고 그 값을 모두 one이라는 IntWritable object로 놓는다. 그러면 map Function의 결과값은 아래와 같게 된다.
첫번째 line :
<"I", 1>, <"love", 1>, <"you", 1>
두번째 line :
<"you", 1>, <"do", 1>, <"not", 1>, <"love", 1>, <"me", 1>, <"I", 1>, <"am", 1>, <"sad", 1>
이 때 하나만 집고 넘어가자. map Function의 Input 값에서 Key에 해당하는 정보는 map Function에서 전혀 쓰이지 않았다는 점이다. MapReduce 함수를 작성하다보면 이런 경우를 굉장히 자주 볼 수 있다. 이것이 옳은 것인지 그른 것인지는 잘 모르겠으나, 내가 몇 개 안되는 MapReduce를 작성해보고 느낀 바로는, 굳이 그렇게 나쁠 것까지는 없다? 정도의 의견을 조심스럽게 말하련다.
아무튼 위와 같은 형태로 <Text, IntWritable>와 같은 Key/Value Pair가 map Function의 output이 되었고 이제 reduce Function의 Input으로 들어가게 된다. reduce Function에서는 이 모든 것을 Key 값을 기준으로 묶고 그 Key가 가지고 있는 output(여기서는 무조건 1이 되겠지)을 더할 예정이다. 그러면 자연스럽게 아래와 같은 결과물이 나오게 된다.
<"I", 2>
<"love", 2>
<"you", 2>
<"do", 1>
<"not", 1>
<"me", 1>
<"am", 1>
<"sad", 1>
결국은 각각의 단어를 세게 되는 것이고, 따라서 WordCount 프로그램이 되는 것이다.
자 이제 마지막으로 이해한 것을 바탕으로 실행시켜보자.
굿굿!! WordCount를 실행시켰다. 결과물도 얻었다. 모두들 잘 이해했기를 바라며 이번 포스팅은 여기서 그만하려한다. 다음 포스팅은 Hadoop Streaming에 대해서 작성할 생각이다.
Reference:
https://hadoop.apache.org/docs/current/api/org/apache/hadoop/mapred/JobConf.html
'Big Data Tech' 카테고리의 다른 글
[Hadoop] Streaming API (0) | 2015.02.01 |
---|---|
[Hadoop] Introduction of Hadoop (0) | 2015.01.31 |
[MongoDB] MongoDB Aggregation (0) | 2014.11.24 |
[MongoDB] CRUD Operation of MongoDB (1) | 2014.11.18 |
[MongoDB] Introduction of MongoDB and its fundamental (0) | 2014.11.09 |