신비로운 Hadoop 정렬의 비밀

HadoopBeginner
지금 연습하기

소개

신비로운 야시장에서 화려한 가면을 쓴 매혹적인 인물이 붐비는 군중 속을 우아하게 움직입니다. 이 수수께끼의 가면 무용수는 비밀스러운 힘을 지닌 듯, 춤을 추며 혼란스러운 노점들을 질서 정연하게 정렬합니다. 여러분의 목표는 Hadoop Shuffle Comparable 기술을 마스터하여 이 놀라운 재능 뒤에 숨겨진 미스터리를 푸는 것입니다.

Mapper 구현

이 단계에서는 입력 데이터를 처리하고 키 - 값 쌍을 내보내기 위해 사용자 정의 Mapper 클래스를 생성합니다. 키는 각 단어의 첫 번째 문자와 단어의 길이로 구성된 복합 키 (composite key) 가 됩니다. 값은 단어 자체입니다.

먼저 사용자를 hadoop으로 변경한 다음 hadoop 사용자의 홈 디렉토리로 전환합니다.

su - hadoop

그런 다음 Mapper 클래스에 대한 Java 파일을 생성합니다.

touch /home/hadoop/WordLengthMapper.java

WordLengthMapper.java 파일에 다음 코드를 추가합니다.

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

public class WordLengthMapper extends Mapper<LongWritable, Text, CompositeKey, Text> {

    private CompositeKey compositeKey = new CompositeKey();

    public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        String line = value.toString();
        String[] words = line.split("\\s+");

        for (String word : words) {
            compositeKey.setFirstChar(word.charAt(0));
            compositeKey.setLength(word.length());
            context.write(compositeKey, new Text(word));
        }
    }
}

위 코드에서 Hadoop MapReduce API 의 Mapper 클래스를 확장하는 WordLengthMapper 클래스를 생성합니다. map 메서드는 LongWritable 키 (입력 줄의 바이트 오프셋을 나타냄) 와 Text 값 (입력 줄 자체) 을 받습니다. 그런 다음 입력 줄을 개별 단어로 분할하고, 각 단어에 대한 CompositeKey 객체 (단어의 첫 번째 문자와 길이를 포함) 를 생성하고, CompositeKey를 키로, 단어를 값으로 내보냅니다.

CompositeKey 구현

이 단계에서는 Hadoop MapReduce API 의 WritableComparable 인터페이스를 구현하는 사용자 정의 CompositeKey 클래스를 생성합니다. 이 클래스는 MapReduce 작업에서 키로 사용되어 각 단어의 첫 번째 문자와 길이를 기준으로 데이터를 정렬하고 그룹화할 수 있습니다.

먼저 CompositeKey 클래스에 대한 Java 파일을 생성합니다.

touch /home/hadoop/CompositeKey.java

그런 다음 CompositeKey.java 파일에 다음 코드를 추가합니다.

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.WritableComparable;

public class CompositeKey implements WritableComparable<CompositeKey> {

    private char firstChar;
    private int length;

    public CompositeKey() {
    }

    public void setFirstChar(char firstChar) {
        this.firstChar = firstChar;
    }

    public char getFirstChar() {
        return firstChar;
    }

    public void setLength(int length) {
        this.length = length;
    }

    public int getLength() {
        return length;
    }

    @Override
    public void write(DataOutput out) throws IOException {
        out.writeChar(firstChar);
        out.writeInt(length);
    }

    @Override
    public void readFields(DataInput in) throws IOException {
        firstChar = in.readChar();
        length = in.readInt();
    }

    @Override
    public int compareTo(CompositeKey other) {
        int cmp = Character.compare(firstChar, other.firstChar);
        if (cmp != 0) {
            return cmp;
        }
        return Integer.compare(length, other.length);
    }

    @Override
    public int hashCode() {
        return firstChar + length;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof CompositeKey) {
            CompositeKey other = (CompositeKey) obj;
            return firstChar == other.firstChar && length == other.length;
        }
        return false;
    }

    @Override
    public String toString() {
        return firstChar + ":" + length;
    }
}

위 코드에서 WritableComparable 인터페이스를 구현하는 CompositeKey 클래스를 생성합니다. 이 클래스는 firstChar (단어의 첫 번째 문자) 와 length (단어의 길이) 의 두 필드를 갖습니다. 이 클래스는 이러한 필드에 대한 getter 및 setter 메서드와 WritableComparable 인터페이스에 필요한 write, readFields, compareTo, hashCode, equals, 및 toString 메서드의 구현을 제공합니다.

compareTo 메서드는 MapReduce 작업에서 키가 정렬되는 방식을 정의하므로 특히 중요합니다. 구현에서 먼저 두 키의 firstChar 필드를 비교합니다. 다르면 해당 비교의 결과를 반환합니다. firstChar 필드가 같으면 length 필드를 비교합니다.

Reducer 구현

이 단계에서는 Mapper 에서 내보낸 키 - 값 쌍을 처리하고 최종 출력을 생성하기 위해 사용자 정의 Reducer 클래스를 생성합니다.

먼저 Reducer 클래스에 대한 Java 파일을 생성합니다.

touch /home/hadoop/WordLengthReducer.java

그런 다음 WordLengthReducer.java 파일에 다음 코드를 추가합니다.

import java.io.IOException;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

public class WordLengthReducer extends Reducer<CompositeKey, Text, CompositeKey, Text> {

    public void reduce(CompositeKey key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
        StringBuilder sb = new StringBuilder();
        for (Text value : values) {
            sb.append(value.toString()).append(", ");
        }
        sb.setLength(sb.length() - 2);
        context.write(key, new Text(sb.toString()));
    }
}

위 코드에서 Hadoop MapReduce API 의 Reducer 클래스를 확장하는 WordLengthReducer 클래스를 생성합니다. reduce 메서드는 CompositeKey 키 (단어의 첫 번째 문자와 길이를 포함) 와 Text 값의 Iterable(키와 일치하는 단어) 을 받습니다.

reduce 메서드 내에서 키와 일치하는 모든 단어를 쉼표로 구분된 문자열로 연결합니다. StringBuilder를 사용하여 출력을 효율적으로 구성하고, 키 - 값 쌍을 출력에 쓰기 전에 후행 쉼표와 공백을 제거합니다.

Driver 구현

이 단계에서는 MapReduce 작업을 구성하고 실행하기 위한 Driver 클래스를 생성합니다.

먼저 Driver 클래스에 대한 Java 파일을 생성합니다.

touch /home/hadoop/WordLengthDriver.java

그런 다음 WordLengthDriver.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 WordLengthDriver {

    public static void main(String[] args) throws Exception {
        if (args.length != 2) {
            System.err.println("Usage: WordLengthDriver <input> <output>");
            System.exit(1);
        }

        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf, "Word Length");

        job.setJarByClass(WordLengthDriver.class);
        job.setMapperClass(WordLengthMapper.class);
        job.setReducerClass(WordLengthReducer.class);
        job.setOutputKeyClass(CompositeKey.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);
    }
}

위 코드에서 MapReduce 작업의 진입점 역할을 하는 WordLengthDriver 클래스를 생성합니다. main 메서드는 작업에 대한 입력 경로와 출력 경로의 두 가지 명령줄 인수를 받습니다.

main 메서드 내에서 새 Configuration 객체와 새 Job 객체를 생성합니다. 매퍼 및 리듀서 클래스, 출력 키 및 값 클래스, 입력 및 출력 경로를 설정하여 작업을 구성합니다.

마지막으로 작업을 제출하고 완료될 때까지 기다립니다. 작업이 성공적으로 완료되면 상태 코드 0 으로 종료하고, 그렇지 않으면 상태 코드 1 로 종료합니다.

작업을 실행하려면 다음 명령을 사용할 수 있습니다.

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/WordLengthMapper.java /home/hadoop/CompositeKey.java /home/hadoop/WordLengthReducer.java /home/hadoop/WordLengthDriver.java
jar cvf word-length.jar *.class
hadoop jar word-length.jar WordLengthDriver /input /output

마지막으로 다음 명령을 실행하여 결과를 확인할 수 있습니다.

hadoop fs -cat /output/*

예시 출력:

A:3 Amr
A:6 AADzCv
A:10 AlGyQumgIl
...
h:7 hgQUIhA
h:8 hyrjMGbY, hSElGKux
h:10 hmfHJjCkwB
...
z:6 zkpRCN
z:8 zfMHRbtk
z:9 zXyUuLHma

요약

이 랩에서는 첫 번째 문자와 길이를 기준으로 단어를 그룹화하는 MapReduce 작업을 구현하여 Hadoop Shuffle Comparable 의 개념을 탐구했습니다. 복합 키를 사용하여 키 - 값 쌍을 내보내는 사용자 정의 Mapper, WritableComparable 인터페이스를 구현하는 사용자 정의 CompositeKey 클래스, 동일한 키를 가진 단어를 연결하는 Reducer, 작업을 구성하고 실행하는 Driver 클래스를 생성했습니다.

이 랩을 통해 Hadoop MapReduce 프레임워크와 분산 컴퓨팅에서 사용자 정의 데이터 유형 및 정렬의 중요성에 대한 더 깊은 이해를 얻었습니다. Hadoop Shuffle Comparable 을 마스터함으로써, 우리는 데이터 처리 및 분석을 위한 효율적인 알고리즘을 설계하여, 혼란스러운 야시장의 노점을 정렬하는 수수께끼의 가면 무용수처럼 빅 데이터의 힘을 열 수 있습니다.