はじめに
恐竜の時代に、勇敢な恐竜ハンターであるアレックスは、これらの史前生物の秘密を解き明かす刺激的なミッションに乗り出します。アレックスの目標は、さまざまなソースから貴重なデータを収集し、高度な分析を行って、さまざまな恐竜種の行動、食性、進化についての洞察を得ることです。
これを達成するために、アレックスは Hadoop MapReduce の力とその効率的な結合操作の能力を活用する必要があります。複数のソースからのデータを結合することで、アレックスは恐竜の化石、その地質学的な場所、および環境条件に関する情報を組み合わせて、恐竜の世界の包括的な画像を描くことができます。
環境とデータのセットアップ
このステップでは、必要な環境をセットアップし、結合操作に使用するデータを準備します。
まず、ユーザーを hadoop に変更してから、hadoop ユーザーのホームディレクトリに切り替えます。
su - hadoop
ファイルを保存するための新しいディレクトリ join-lab を作成します。
mkdir join-lab
cd join-lab
次に、2 つのデータファイル dinosaurs.txt と locations.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-lab を hdfs にアップロードします。
hadoop fs -mkdir -p /home/hadoop
hadoop fs -put /home/hadoop/join-lab /home/hadoop/
結合操作を実装する
このステップでは、MapReduce ジョブを実装して、dinosaurs.txt と locations.txt ファイルに対して結合操作を行います。
/home/hadoop/join-lab ディレクトリに、以下の内容を持つ新しい Java ファイル JoinDinosaurs.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);
}
}
このコードは、カスタムの JoinMapper と JoinReducer を持つ MapReduce ジョブを定義しています。マッパーは dinosaurs.txt と locations.txt から入力データを読み取り、恐竜の名前をキーとして、データ型("DIN" または "LOC")と対応する値を含むキーバリューペアを出力します。その後、リデューサはキーで値をグループ化し、恐竜の情報と場所を結合することで結合操作を行います。
コードをコンパイルするには、以下のコマンドを実行します。
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.txt と locations.txt が含まれています)と出力ディレクトリ /home/hadoop/join-lab/output を指定します。
ジョブが正常に完了した後、/home/hadoop/join-lab/output ディレクトリに出力を表示できます。
出力を分析する
このステップでは、結合操作の出力を分析して、恐竜の世界に関する洞察を得ます。
まず、出力ディレクトリの内容を確認しましょう。
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
この出力は、結合されたデータを示しており、各行には恐竜の名前、その詳細(種類と食性)、およびその化石が見つかった場所が含まれています。
出力を基に、以下のような観察ができます。
- 「ティラノサウルス・レックス」(T-Rex)と「ベロシラプトル」は肉食性の恐竜であり、「ブラキオサウルス」と「ステゴサウルス」は草食性でした。
- 「ブラキオサウルス」の化石はアフリカで見つかり、「ステゴサウルス」と「ティラノサウルス・レックス」の化石は北アメリカで見つかり、「ベロシラプトル」の化石はアジアで見つかりました。
これらの洞察は、古生物学者が異なる地質学的地域にわたるさまざまな恐竜種の分布、行動、進化をよりよく理解するのに役立ちます。
まとめ
この実験では、Hadoop MapReduce を使った結合操作の実装を検討しました。複数のソースからのデータを組み合わせることで、恐竜の世界、その種類、食性、化石の場所などに関する貴重な洞察を得ることができました。
この実験では、MapReduce を使ってデータを結合する概念を紹介しました。マッパーは結合操作のためのデータを準備し、リデューサはキーで値をグループ化し、情報を結合することで実際の結合を行います。
環境のセットアップ、データの準備、MapReduce ジョブの実装、出力の分析という実践的な経験を通じて、Hadoop の強力なデータ処理機能を活用して複雑な分析問題を解決する方法に関する実践的な知識を得ました。
この実験は、結合操作の理解を深めるだけでなく、Hadoop MapReduce の使用、Java コードの記述、Linux 環境でのコマンドの実行に関するスキルを強化しました。ゼロから完全なソリューションを設計して実装する経験は非常に貴重であり、データエンジニアまたはデータサイエンティストとしての成長に確実に貢献するでしょう。



