引言
在一片广袤的沙漠荒原中,一位孤独的商人踏上了一段充满危险的旅程,试图揭开隐藏在炙热沙层下的秘密。商人的目标是发现古代遗物和文物,解开一个早已被遗忘的文明的秘密。然而,沙漠中埋藏的海量数据构成了巨大的挑战,需要借助 Hadoop MapReduce 的力量来有效地处理和分析这些信息。
在一片广袤的沙漠荒原中,一位孤独的商人踏上了一段充满危险的旅程,试图揭开隐藏在炙热沙层下的秘密。商人的目标是发现古代遗物和文物,解开一个早已被遗忘的文明的秘密。然而,沙漠中埋藏的海量数据构成了巨大的挑战,需要借助 Hadoop MapReduce 的力量来有效地处理和分析这些信息。
在这一步骤中,我们将创建一个 Mapper 类来处理从沙漠挖掘中获取的原始数据。我们的目标是从数据中提取相关信息,并为其进一步分析做好准备,以便 Reducer 进行处理。
使用 su - hadoop
命令切换到 hadoop 用户,并自动进入 /home/hadoop
目录。此时,使用 ls .
命令可以看到数据文件 data*.txt
。然后根据以下代码在该目录中创建并填充 ArtifactMapper.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 ArtifactMapper extends Mapper<LongWritable, Text, Text, LongWritable> {
private final static LongWritable ONE = new LongWritable(1);
private Text word = new Text();
@Override
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
// Split the line into words
String[] tokens = value.toString().split("\\s+");
// Emit each word with a count of 1
for (String token : tokens) {
word.set(token);
context.write(word, ONE);
}
}
}
在 ArtifactMapper
类中,我们扩展了 Hadoop 提供的 Mapper
类。map
方法被重写以处理每个输入的键值对。
LongWritable
,表示输入行的字节偏移量,输入值是一个 Text
对象,包含输入文件中的一行文本。map
方法使用 split
方法和正则表达式 "\\s+"
将输入行拆分为单个单词,以匹配一个或多个空白字符。map
方法创建一个 Text
对象并将其作为键发出,同时发出一个常量 LongWritable
值 1
作为值,表示该单词的计数。在这一步骤中,我们将创建一个 Reducer 类来聚合 Mapper 发出的数据。Reducer 将统计每个单词的出现次数,并生成最终输出。
根据以下代码内容,在 /home/hadoop
目录中创建并填充 ArtifactReducer.java
文件:
import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
public class ArtifactReducer extends Reducer<Text, LongWritable, Text, LongWritable> {
@Override
public void reduce(Text key, Iterable<LongWritable> values, Context context)
throws IOException, InterruptedException {
long sum = 0;
for (LongWritable value : values) {
sum += value.get();
}
context.write(key, new LongWritable(sum));
}
}
在 ArtifactReducer
类中,我们扩展了 Hadoop 提供的 Reducer
类。reduce
方法被重写以聚合与每个键关联的值。
Text
对象,表示单词,输入值是一个 LongWritable
对象的 Iterable
,表示由 Mappers 发出的该单词的计数。reduce
方法遍历这些值,并计算给定单词的所有计数的总和。reduce
方法随后使用 context.write
发出单词作为键,并将总计数作为值。在这一步骤中,我们将创建一个 Driver 类来协调 MapReduce 作业。Driver 将配置作业,指定输入和输出路径,并将作业提交到 Hadoop 集群。
根据以下代码内容,在 /home/hadoop
目录中创建并填充 ArtifactDriver.java
文件:
import org.apache.hadoop.conf.Configuration;
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.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class ArtifactDriver {
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf, "Artifact Word Count");
// Specify the job's jar file by class
job.setJarByClass(ArtifactDriver.class);
// Set the Mapper and Reducer classes
job.setMapperClass(ArtifactMapper.class);
job.setReducerClass(ArtifactReducer.class);
// Set the output key and value types
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(LongWritable.class);
// Set the input and output paths
FileInputFormat.addInputPath(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
// Submit the job and wait for completion
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
在 ArtifactDriver
类中,我们创建了一个 MapReduce 作业,并配置它以运行我们的 ArtifactMapper
和 ArtifactReducer
类。
main
方法创建了一个新的 Configuration
对象和一个名为 "Artifact Word Count" 的 Job
对象。setMapperClass
和 setReducerClass
方法用于指定作业中使用的 Mapper 和 Reducer 类。setOutputKeyClass
和 setOutputValueClass
方法用于指定作业的输出键和值类型。FileInputFormat.addInputPath
方法用于指定作业的输入路径,该路径作为第一个命令行参数传入。FileOutputFormat.setOutputPath
方法用于指定作业的输出路径,该路径作为第二个命令行参数传入。job.waitForCompletion
方法被调用来提交作业并等待其完成。如果作业成功,程序将以状态码 0 退出;如果失败,则以状态码 1 退出。在这一步骤中,我们将编译 Java 类并在 Hadoop 集群上运行 MapReduce 作业。
首先,我们需要编译 Java 类:
javac -source 8 -target 8 -classpath $HADOOP_HOME/share/hadoop/common/hadoop-common-3.3.6.jar:$HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-client-core-3.3.6.jar:. *.java
此命令编译 Java 类并将编译后的 .class
文件放置在当前目录中。-classpath
选项包含了 Hadoop 库路径,这些路径是编译使用 Hadoop 类的代码所必需的。-source
和 -target
参数用于指定 Java 源代码和目标字节码版本,以匹配 Hadoop 中的 Java 版本。
接下来,使用 jar
命令打包 class
文件:
jar -cvf Artifact.jar *.class
最后,我们可以运行 MapReduce 作业,所有关于沙漠的数据已经存储在 HDFS 的 /input
目录中:
hadoop jar Artifact.jar ArtifactDriver /input /output
执行命令后,你应该会看到指示 MapReduce 作业进度的日志。作业完成后,你可以在 HDFS 的 /output
目录中找到输出文件。并使用以下命令查看结果:
hdfs dfs -ls /output
hdfs dfs -cat /output/part-r-00000
恭喜你!你已经成功探索了为 Hadoop MapReduce 作业编写 Mapper 和 Reducer 的过程。在一个涉及沙漠商人寻找古代遗迹的场景中,你利用 Hadoop MapReduce 的强大功能分析了大量的沙漠数据。通过实现 ArtifactMapper
类提取了相关数据,而 ArtifactReducer
类则聚合了 Mapper 的输出。通过 ArtifactDriver
类协调整个过程,进一步巩固了你的理解。在整个过程中,我们强调了最佳实践、完整的代码示例和验证检查。这种实践经验加深了你对 Hadoop MapReduce 的理解,并突出了有效的学习体验设计。