소개
고대 그리스 올림픽에서, 전국의 운동선수들이 모여 자신의 기량을 뽐내고 다양한 운동 경기에 참가했습니다. 알렉시오스라는 한 선수는 다가오는 경기를 위해 쉼 없이 훈련하며 자신의 도시 국가에 영광을 안겨주기로 결심했습니다.
목표는 참가자들을 그들의 경기에 따라 다른 그룹으로 분류하고 조직하여 공정하고 효율적인 경쟁을 보장하는 것이었습니다. 그러나 영광을 위해 경쟁하는 수백 명의 운동선수들을 각자의 경기에 배정하는 일은 매우 어려운 과제였습니다.
Mapper 구현
이 단계에서는 입력 데이터를 읽고 Partitioner 가 처리할 key-value 쌍을 생성하는 Mapper 클래스를 만들 것입니다.
먼저, 사용자를 hadoop으로 변경한 다음 hadoop 사용자의 홈 디렉토리로 전환합니다.
su - hadoop
그런 다음, Mapper 클래스를 위한 Java 파일을 생성합니다.
touch /home/hadoop/OlympicMapper.java
다음 코드를 OlympicMapper.java 파일에 추가합니다.
import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
public class OlympicMapper extends Mapper<LongWritable, Text, Text, Text> {
@Override
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
String[] fields = value.toString().split(",");
String athlete = fields[0];
String event = fields[1];
context.write(new Text(event), new Text(athlete));
}
}
OlympicMapper 클래스에서 입력 키는 LongWritable (행 오프셋을 나타냄) 로 정의하고 입력 값은 Text (입력 파일의 텍스트 행을 나타냄) 로 정의합니다. 출력 키는 이벤트를 나타내는 Text 객체이고, 출력 값은 운동선수의 이름을 나타내는 Text 객체입니다.
map 메서드는 입력 데이터의 각 행을 쉼표 구분 기호로 분할하고, 운동선수의 이름과 이벤트를 추출하여 이벤트를 키로, 운동선수의 이름을 값으로 하는 key-value 쌍을 내보냅니다.
Partitioner 구현
이 단계에서는 이벤트를 기반으로 key-value 쌍을 분할하는 사용자 정의 Partitioner 클래스를 만들 것입니다.
먼저, Partitioner 클래스를 위한 Java 파일을 생성합니다.
touch /home/hadoop/OlympicPartitioner.java
그런 다음, 다음 코드를 OlympicPartitioner.java 파일에 추가합니다.
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Partitioner;
public class OlympicPartitioner extends Partitioner<Text, Text> {
@Override
public int getPartition(Text key, Text value, int numPartitions) {
return Math.abs(key.hashCode() % numPartitions);
}
}
OlympicPartitioner 클래스는 Hadoop 에서 제공하는 Partitioner 클래스를 확장합니다. getPartition 메서드를 재정의하며, 이 메서드는 키, 값 및 파티션 수를 입력으로 받습니다.
getPartition 메서드는 이벤트 (키) 에 대한 해시 코드를 계산하고, 해시 코드의 절대값을 파티션 수로 나눈 나머지 값을 취하여 파티션 번호를 반환합니다. 이렇게 하면 동일한 이벤트를 가진 모든 레코드가 Reducer 에 의해 처리될 동일한 파티션으로 전송되도록 보장합니다.
Reducer 구현
이 단계에서는 분할된 데이터를 처리하고 최종 출력을 생성하는 Reducer 클래스를 만들 것입니다.
먼저, Reducer 클래스를 위한 Java 파일을 생성합니다.
touch /home/hadoop/OlympicReducer.java
그런 다음, 다음 코드를 OlympicReducer.java 파일에 추가합니다.
import java.io.IOException;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
public class OlympicReducer extends Reducer<Text, Text, Text, Text> {
@Override
protected void reduce(Text key, Iterable<Text> values, Context context)
throws IOException, InterruptedException {
StringBuilder athletes = new StringBuilder();
for (Text value : values) {
athletes.append(value.toString()).append(",");
}
if (athletes.length() > 0) {
athletes.deleteCharAt(athletes.length() - 1);
}
context.write(key, new Text(athletes.toString()));
}
}
OlympicReducer 클래스는 Hadoop 에서 제공하는 Reducer 클래스를 확장합니다. 입력 키는 Text (이벤트를 나타냄), 입력 값은 Text (운동선수의 이름을 나타냄), 출력 키와 값은 Text 객체로 정의합니다.
reduce 메서드는 각 고유한 이벤트 키에 대해 호출되며, 해당 이벤트와 관련된 운동선수 이름에 대한 반복기가 제공됩니다. 각 이벤트에 대한 쉼표로 구분된 운동선수 목록을 생성하고, 이벤트를 키로, 운동선수 목록을 값으로 하는 key-value 쌍을 내보냅니다.
Driver 작성
이 단계에서는 Mapper, Partitioner 및 Reducer 클래스를 연결하고 MapReduce 작업을 실행하는 Driver 클래스를 만들 것입니다.
먼저, Driver 클래스를 위한 Java 파일을 생성합니다.
touch /home/hadoop/OlympicDriver.java
그런 다음, 다음 코드를 OlympicDriver.java 파일에 추가합니다.
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
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.output.FileOutputFormat;
public class OlympicDriver {
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf, "Olympic Partitioner");
job.setJarByClass(OlympicDriver.class);
job.setMapperClass(OlympicMapper.class);
job.setPartitionerClass(OlympicPartitioner.class);
job.setReducerClass(OlympicReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
FileInputFormat.addInputPath(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
OlympicDriver 클래스는 MapReduce 작업의 진입점입니다. 작업 구성을 설정하고, Mapper, Partitioner 및 Reducer 클래스를 지정하며, 입력 및 출력 경로를 구성합니다.
main 메서드에서 새로운 Configuration 객체와 작업 이름이 "Olympic Partitioner"인 Job 인스턴스를 생성합니다. 해당 설정 메서드를 사용하여 Mapper, Partitioner 및 Reducer 클래스를 설정합니다.
또한 출력 키와 값 클래스를 Text로 설정합니다. 입력 및 출력 경로는 드라이버에 전달된 명령줄 인수를 사용하여 지정됩니다.
마지막으로, Job 인스턴스에서 waitForCompletion 메서드를 호출하여 MapReduce 작업을 실행하고 적절한 상태 코드 (성공 시 0, 실패 시 1) 로 종료합니다.
작업을 실행하려면 Java 클래스를 컴파일하고 jar 파일을 생성해야 합니다. 그런 다음 다음 명령을 사용하여 jar 파일을 실행할 수 있습니다.
javac -source 8 -target 8 -classpath "/home/hadoop/:/home/hadoop/hadoop/share/hadoop/common/hadoop-common-3.3.6.jar:/home/hadoop/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-client-core-3.3.6.jar:/home/hadoop/hadoop/share/hadoop/common/lib/*" -d /home/hadoop /home/hadoop/OlympicMapper.java /home/hadoop/OlympicPartitioner.java /home/hadoop/OlympicReducer.java /home/hadoop/OlympicDriver.java
jar cvf olympic.jar *.class
hadoop jar olympic.jar OlympicDriver /input /output
마지막으로, 다음 명령을 실행하여 결과를 확인할 수 있습니다.
hadoop fs -cat /output/*
예시 출력:
Event_1 Athlete_17,Athlete_18,Athlete_79,Athlete_71,Athlete_77,Athlete_75,Athlete_19,Athlete_24,Athlete_31,Athlete_32,Athlete_39,Athlete_89,Athlete_88,Athlete_87,Athlete_100,Athlete_13,Athlete_52,Athlete_53,Athlete_58
Event_2 Athlete_1,Athlete_97,Athlete_96,Athlete_85,Athlete_81,Athlete_80,Athlete_72,Athlete_68,Athlete_64,Athlete_61,Athlete_54,Athlete_48,Athlete_47,Athlete_43,Athlete_28,Athlete_23,Athlete_21,Athlete_15,Athlete_12,Athlete_3
Event_3 Athlete_11,Athlete_55,Athlete_8,Athlete_46,Athlete_42,Athlete_41,Athlete_40,Athlete_38,Athlete_33,Athlete_92,Athlete_29,Athlete_27,Athlete_25,Athlete_93,Athlete_22,Athlete_20,Athlete_98,Athlete_14,Athlete_69,Athlete_99,Athlete_66,Athlete_65
Event_4 Athlete_90,Athlete_50,Athlete_37,Athlete_36,Athlete_91,Athlete_74,Athlete_73,Athlete_63,Athlete_26,Athlete_78,Athlete_5,Athlete_62,Athlete_60,Athlete_59,Athlete_82,Athlete_4,Athlete_51,Athlete_86,Athlete_2,Athlete_94,Athlete_7,Athlete_95
Event_5 Athlete_34,Athlete_76,Athlete_57,Athlete_56,Athlete_30,Athlete_16,Athlete_6,Athlete_10,Athlete_83,Athlete_84,Athlete_70,Athlete_45,Athlete_44,Athlete_49,Athlete_9,Athlete_67,Athlete_35
요약
이 Lab 에서는 고대 그리스 올림픽에서 영감을 얻은 시나리오를 설계하여 Hadoop Shuffle Partitioner 의 개념을 탐구했습니다. 입력 데이터를 읽고 key-value 쌍을 생성하는 Mapper 클래스, 이벤트를 기반으로 데이터를 분할하는 사용자 지정 Partitioner 클래스, 분할된 데이터를 처리하고 최종 출력을 생성하는 Reducer 클래스를 구현했습니다.
이 Lab 을 통해 MapReduce 프로그래밍 모델에 대한 실질적인 경험을 얻었으며, Partitioner 클래스를 활용하여 데이터를 파티션 간에 효율적으로 분산하는 방법을 배웠습니다. 고대 그리스 올림픽 시나리오는 Shuffle Partitioner 의 실제 적용 사례를 현실 세계에서 이해할 수 있는 매력적인 맥락을 제공했습니다.



