Hadoop 을 이용한 공룡 데이터 융합

HadoopBeginner
지금 연습하기

소개

공룡 시대에, 알렉스라는 용감한 공룡 사냥꾼이 이 선사 시대 생물들의 비밀을 밝히는 흥미진진한 임무를 시작합니다. 알렉스의 목표는 다양한 소스에서 귀중한 데이터를 수집하고, 고급 분석을 수행하여 다양한 공룡 종의 행동, 식단, 그리고 진화에 대한 통찰력을 얻는 것입니다.

이를 위해 알렉스는 Hadoop MapReduce 의 강력한 기능을 활용하여 효율적으로 join 연산을 수행해야 합니다. 여러 소스의 데이터를 join 함으로써, 알렉스는 공룡 화석, 지질학적 위치, 그리고 환경 조건에 대한 정보를 결합하여 공룡 세계에 대한 포괄적인 그림을 그릴 수 있습니다.

환경 및 데이터 설정

이 단계에서는 필요한 환경을 설정하고 join 연산을 위한 데이터를 준비합니다.

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

su - hadoop

파일을 저장할 join-lab이라는 새 디렉토리를 생성합니다:

mkdir join-lab
cd join-lab

다음으로, dinosaurs.txtlocations.txt 두 개의 데이터 파일을 생성해 보겠습니다. 이 파일들은 각각 공룡과 화석 위치에 대한 정보를 담고 있습니다.

다음 내용으로 dinosaurs.txt를 생성합니다:

trex,Tyrannosaurus Rex,carnivore
velociraptor,Velociraptor,carnivore
brachiosaurus,Brachiosaurus,herbivore
stegosaurus,Stegosaurus,herbivore

다음 내용으로 locations.txt를 생성합니다:

trex,North America
velociraptor,Asia
brachiosaurus,Africa
stegosaurus,North America

마지막으로, 다음 명령을 사용하여 join-labhdfs에 업로드합니다:

hadoop fs -mkdir -p /home/hadoop
hadoop fs -put /home/hadoop/join-lab /home/hadoop/

Join 연산 구현

이 단계에서는 dinosaurs.txtlocations.txt 파일에 대한 join 연산을 수행하는 MapReduce 작업을 구현합니다.

/home/hadoop/join-lab 디렉토리에 다음 내용으로 JoinDinosaurs.java라는 새 Java 파일을 생성합니다:

import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
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;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class JoinDinosaurs {

    public static class JoinMapper extends Mapper<LongWritable, Text, Text, Text> {
        private final Text outKey = new Text();
        private final Text outValue = new Text();

        @Override
        protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
            String line = value.toString();
            String[] parts = line.split(",");

            if (parts.length == 2) { // locations.txt
                outKey.set(parts[0]);
                outValue.set("LOC:" + parts[1]);
            } else if (parts.length == 3) { // dinosaurs.txt
                outKey.set(parts[0]);
                outValue.set("DIN:" + parts[1] + "," + parts[2]);
            }

            context.write(outKey, outValue);
        }
    }

    public static class JoinReducer extends Reducer<Text, Text, Text, Text> {
        private final Text outValue = new Text();

        @Override
        protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
            Map<String, String> dinMap = new HashMap<>();
            StringBuilder locBuilder = new StringBuilder();

            for (Text value : values) {
                String valStr = value.toString();
                if (valStr.startsWith("DIN:")) {
                    dinMap.put("DIN", valStr.substring(4));
                } else if (valStr.startsWith("LOC:")) {
                    locBuilder.append(valStr.substring(4)).append(",");
                }

                if (locBuilder.length() > 0) {
                    locBuilder.deleteCharAt(locBuilder.length() - 1);
                }
            }

            StringBuilder outBuilder = new StringBuilder();
            for (Map.Entry<String, String> entry : dinMap.entrySet()) {
                outBuilder.append(entry.getValue()).append("\t").append(locBuilder.toString().trim());
            }

            outValue.set(outBuilder.toString());
            context.write(key, outValue);
        }
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        if (args.length != 2) {
            System.err.println("Usage: JoinDinosaurs <input_dir> <output_dir>");
            System.exit(1);
        }

        Job job = Job.getInstance();
        job.setJarByClass(JoinDinosaurs.class);
        job.setJobName("Join Dinosaurs");

        FileInputFormat.addInputPath(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));

        job.setMapperClass(JoinMapper.class);
        job.setReducerClass(JoinReducer.class);

        job.setInputFormatClass(TextInputFormat.class);
        job.setOutputFormatClass(TextOutputFormat.class);

        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(Text.class);

        System.exit(job.waitForCompletion(true) ? 0 : 1);
    }
}

이 코드는 사용자 정의 JoinMapperJoinReducer를 사용하여 MapReduce 작업을 정의합니다. 매퍼는 dinosaurs.txtlocations.txt에서 입력 데이터를 읽고, 공룡 이름을 키로, 데이터 유형 ("DIN" 또는 "LOC") 과 해당 값을 값으로 하는 키 - 값 쌍을 내보냅니다. 그런 다음 리듀서는 키별로 값을 그룹화하고 공룡 정보와 위치를 결합하여 join 연산을 수행합니다.

코드를 컴파일하려면 다음 명령을 실행합니다:

mkdir classes
javac -source 8 -target 8 -cp "/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 classes JoinDinosaurs.java
jar -cvf join-dinosaurs.jar -C classes/ .

다음으로, 다음 명령을 사용하여 MapReduce 작업을 실행합니다:

hadoop jar join-dinosaurs.jar JoinDinosaurs /home/hadoop/join-lab /home/hadoop/join-lab/output

이 명령은 join-dinosaurs.jar 파일에서 JoinDinosaurs 클래스를 실행하며, 입력 디렉토리 /home/hadoop/join-lab ( dinosaurs.txtlocations.txt 포함) 와 출력 디렉토리 /home/hadoop/join-lab/output을 사용합니다.

작업이 성공적으로 완료되면 /home/hadoop/join-lab/output 디렉토리에서 출력을 볼 수 있습니다.

출력 분석

이 단계에서는 join 연산의 출력을 분석하여 공룡 세계에 대한 통찰력을 얻습니다.

먼저, 출력 디렉토리의 내용을 확인해 보겠습니다:

hadoop fs -ls /home/hadoop/join-lab/output
hadoop fs -cat /home/hadoop/join-lab/output/part-r-00000

다음과 유사한 출력을 볼 수 있습니다:

brachiosaurus    Brachiosaurus,herbivore    Africa
stegosaurus      Stegosaurus,herbivore      North America
trex     Tyrannosaurus Rex,carnivore        North America
velociraptor     Velociraptor,carnivore     Asia

이 출력은 join 된 데이터를 보여주며, 각 줄에는 공룡 이름, 세부 정보 (종 및 식단), 그리고 화석이 발견된 위치가 포함되어 있습니다.

출력을 기반으로 다음과 같은 관찰을 할 수 있습니다:

  • Tyrannosaurus Rex (T-Rex) 와 Velociraptor는 육식 공룡이었고, BrachiosaurusStegosaurus는 초식 공룡이었습니다.
  • Brachiosaurus 화석은 아프리카에서, StegosaurusTyrannosaurus Rex 화석은 북미에서, 그리고 Velociraptor 화석은 아시아에서 발견되었습니다.

이러한 통찰력은 고생물학자들이 서로 다른 지질학적 지역에서 다양한 공룡 종의 분포, 행동 및 진화를 더 잘 이해하는 데 도움이 될 수 있습니다.

요약

이 Lab 에서는 Hadoop MapReduce 를 사용하여 join 연산을 구현하는 방법을 살펴보았습니다. 여러 소스의 데이터를 결합하여 공룡의 종, 식단, 화석 위치를 포함한 공룡 세계에 대한 귀중한 통찰력을 얻을 수 있었습니다.

이 Lab 에서는 MapReduce 를 사용하여 데이터를 join 하는 개념을 소개했습니다. 여기서 매퍼는 join 연산을 위해 데이터를 준비하고, 리듀서는 키별로 값을 그룹화하고 정보를 결합하여 실제 join 을 수행합니다.

환경 설정, 데이터 준비, MapReduce 작업 구현, 출력 분석과 같은 실습을 통해 Hadoop 의 강력한 데이터 처리 기능을 활용하여 복잡한 분석 문제를 해결하는 방법에 대한 실질적인 지식을 얻었습니다.

이 Lab 은 join 연산에 대한 이해를 높였을 뿐만 아니라 Hadoop MapReduce 작업, Java 코드 작성, Linux 환경에서 명령 실행과 관련된 기술을 강화했습니다. 처음부터 완전한 솔루션을 설계하고 구현한 경험은 매우 귀중했으며, 데이터 엔지니어 또는 데이터 과학자로서의 성장에 기여할 것입니다.