第四章 编写基本的MapReduce程序
4.3 数量统计
许多外行人认为统计学就是数量统计,并且许多基本的Hadoop Job就是用于统计数量的。我们已经在第一章中看过统计单词个数的例子了。对于那些专利引用数据,我们可能想要知道专利被引用的次数。这也是一种数量统计。我们期望得到如下形式的结果:
1 2
10000 1
100000 1
1000006 1
1000007 1
1000011 1
1000017 1
1000026 1
1000033 2
1000043 1
1000044 2
1000045 1
1000046 2
1000049 1
1000051 1
1000054 1
1000065 1
1000067 3
在每条记录中,专利号与它被引用的次数关联。我们可以编写MapReduce程序来执行这项任务。就像我们之前说的那样,您几乎不会重头编写一个MapReduce程序。您已经有了一个以类似的方式处理数据的MapReduce程序。您需要复制并修改它,直到符合您的要求。
我们之前写过一个以相反的次序显示引用记录的程序。我们可以使程序显示引用次数,而不是引用的专利的列表。我们需要修改Reducer。如果我们选择将引用次数作为IntWritable,我们需要在Reducer代码中的三个地方指定IntWritable。我们在前置注解中将它们称为V3。
public static class Reduce extends MapReduceBase implements
Reducer<Text, Text, Text, IntWritable> {
public void reduce(Text key, Iterator<Text> values,
OutputCollector<Text, IntWritable> output, Reporter reporter)
throws IOException {
int count = 0;
while (values.hasNext()) {
values.next();
count++;
}
output.collect(key, new IntWritable(count));
}
}
通过修改少量的代码行来与类型匹配,我们获得了一个新的MapReduce程序。这个程序看起来只有很小的改动,让我们看看另一个需要更多改动的例子,您会发现它仍然会保留基本的MapReduce程序的结构。
在运行之前的例子之后,我们现在有了统计每个专利被引用的次数的数据。一个有趣的练习是对统计结果进行计数。我们预期大量的专利可能只会被引用一次,而少数的专利将会被引用几百次。观察引用次数的分布是一件有趣的事情。
请注意
专利引用数据集只涵盖了1975年到1999年发布的专利,引用计数可能被低估。(在那个时期之外的专利引用不会被统计。)我们也不会处理被应用0次的专利。尽管有这些警告,这种分析还是很实用的。
编写MapReduce程序的第一步是弄清楚数据流。在这种情况下,mapper读取记录时,忽略了专利号,并输出中间键/值对<citation_count, 1>。reducer会将每个引用计数加1,并将总数输出。
在弄清楚数据流之后,需要决定键值对的类型——K1、V1,K2、 V2, K3和V3,分别用于输入、中间结果和输出键/值对。我们将使用KeyValueTextInputFormat类型,它将自动地将每个输入记录分解为基于分隔符的键/值对。输出格式将K1和V1作为文本进行处理。我们选择IntWritable类作为K2、V2、K3和V3的类型,因为我们知道那些数据肯定是整数,并且使用IntWritable的性能更好。
根据数据流和数据类型,您就可以看到清单 4.2中列出的最终程序,并理解它是做什么的了。您可以看到,它在结构上与我们到此为止看到的其他MapReduce很相似。我们将在清单后面探讨细节。
清单 4.2 CitationHistogram.java: 统计被引用一次、两次及其他次数的专利的数量
public class CitationHistogram extends Configured implements Tool {
public static class MapClass extends MapReduceBase implements
Mapper<Text, Text, IntWritable, IntWritable> {
private final static IntWritable uno = new IntWritable(1);
private IntWritable citationCount = new IntWritable();
public void map(Text key, Text value,
OutputCollector<IntWritable, IntWritable> output,
Reporter reporter) throws IOException {
citationCount.set(Integer.parseInt(value.toString()));
output.collect(citationCount, uno);
}
}
public static class Reduce extends MapReduceBase implements
Reducer<IntWritable, IntWritable, IntWritable, IntWritable> {
public void reduce(IntWritable key, Iterator<IntWritable> values,
OutputCollector<IntWritable, IntWritable> output,
Reporter reporter) throws IOException {
int count = 0;
while (values.hasNext()) {
count += values.next().get();
}
output.collect(key, new IntWritable(count));
}
}
public int run(String[] args) throws Exception {
Configuration conf = getConf();
JobConf job = new JobConf(conf, CitationHistogram.class);
Path in = new Path(args[0]);
Path out = new Path(args[1]);
FileInputFormat.setInputPaths(job, in);
FileOutputFormat.setOutputPath(job, out);
job.setJobName("CitationHistogram");
job.setMapperClass(MapClass.class);
job.setReducerClass(Reduce.class);
job.setInputFormat(KeyValueTextInputFormat.class);
job.setOutputFormat(TextOutputFormat.class);
job.setOutputKeyClass(IntWritable.class);
job.setOutputValueClass(IntWritable.class);
JobClient.runJob(job);
return 0;
}
public static void main(String[] args) throws Exception {
int res = ToolRunner.run(new Configuration(), new CitationHistogram(), args);
System.exit(res);
}
}
类型现在是CitationHistogram;所有对MyJob的引用都被更改为对新名称的引用。main()方法几乎永远是一样的。dirver也几乎没有修改。输入和输出的类型仍然分别是KeyValueTextInputFormat和TextOutputFormat。主要的改变是输出键类和输出值类现在是IntWritable,与对应K2和V2的新类型对应。我们也移除了下面的代码行:
job.set("key.value.separator.in.input.line", ",");
这行代码设置了KeyValueTextInputFormat使用的分隔符,来将每个输入行分解为键/值对。不设置这个属性的话,它的默认值是tab字符,与专利引用数据的格式相符。
这个mapper的数据流与之前的mapper的数据流相似,只是这里我们选择定义并使用一对类变量——citationCount和uno。
public static class MapClass extends MapReduceBase implements
Mapper<Text, Text, IntWritable, IntWritable> {
private final static IntWritable uno = new IntWritable(1);
private IntWritable citationCount = new IntWritable();
public void map(Text key, Text value,
OutputCollector<IntWritable, IntWritable> output, Reporter reporter)
throws IOException {
citationCount.set(Integer.parseInt(value.toString()));
output.collect(citationCount, uno);
}
}
map()方法增加了一行,用于在设置citationCount时进行类型转换。在类中定义citationCount和uno,而不是在方法中,这纯粹是为了性能。map方法会在有多条记录(为每个JVM进行分隔)时被调用多次。减少在map()中创建的对象的数量可以提升性能并减少垃圾回收。由于我们向output.collect()中传递citationCount和uno,我们需要依赖于output.collect()方法的约定,避免修改那两个对象。(我们会在第5.1.3小节中看到,这种依赖会禁止ChainMapper使用传引用(pass-by-reference)方式)
reducer将每个键的值相加。这看起来性能不好,因为我们知道这些值都是1(准确地说,是uno)。为什么我们需要将计数相加?我们已经考虑了性能。与MapClass不同,Reduce中的output.collect()调用将会实例化一个新的IntWritable,而不是重用已经存在的那个。
output.collect(key, new IntWritable(count));
我们可以通过使用IntWritable类变量来提高性能,但在这个程序中,reduce()被调用的次数要少得多,可能不会超过1000次(在所有的reducer中)。我们不需要对这些特定的代码进行优化。
执行 MapReduce job,并使用引用计数数据,将会显示下列结果。就像我们预期的那样,大量(超过900K)专利只被引用一次,而有些专利被引用了几百次。最热门的专利被引用了779次。
1 921128
2 552246
3 380319
4 278438
5 210814
6 163149
7 127941
8 102155
9 82126
10 66634
...
411 1
605 1
613 1
631 1
633 1
654 1
658 1
678 1
716 1
779 1
由于这个直方图形式的输出只有几百行代码,我们可以把它放到电子表格中并图形化。图 4.2显示了不同引用频率的专利的数量。这个曲线是按对数趋势变化的。当一个分布显示出对数趋势的曲线时,它就被称为幂率分布(power law distribution)。引用计数直方图看起来是符合这种描述的,尽管它的大致抛物线曲率也暗示着它是一个对数正态分布。
就像您在到目前为止看到的那样,MapReduce程序通常不大,并且您可以保持一种特定的结构,以简化部署。大多数的工作是考虑数据流。
图 4.2 将不同引用频率下的专利的数量图形化。许多专利只被引用一次(或者完全没有,在这张图中没有体现出来)。某些专利被引用了几百次。在对数图上,这看起来与直线十分接近,这被称为幂次分布。
分享到:
相关推荐
《Hadoop权威指南中文版(第二版)》与《Hadoop in Action》及《Pro Hadoop》这三本书是深入理解和掌握Hadoop生态系统的关键资源。Hadoop作为一个分布式计算框架,其核心是解决大规模数据处理的问题,它允许在廉价...
- **第2章:启动Hadoop**:介绍了如何安装和配置Hadoop环境,包括单机模式、伪分布式模式以及完全分布式模式下的安装步骤。 - **第3章:Hadoop的组成部分**:详细介绍了Hadoop的核心组件,如HDFS、MapReduce、YARN...
4. **YARN资源管理器**:YARN(Yet Another Resource Negotiator)是Hadoop的第二代资源管理系统,它将资源管理和作业调度分离,提高了集群的利用率和多任务处理能力。 5. **数据分片与容错机制**:Hadoop通过数据...
第四章Writing basic MapReduce programs为读者展示了编写基础MapReduce程序的方法,通过编写Map和Reduce函数来实现数据处理。第五章Advanced MapReduce继续深入探讨更高级的MapReduce技术,包括优化MapReduce作业和...
### Hadoop in Action:深入解析Hadoop关键技术与应用 #### 核心概念与技术要点 在探讨《Hadoop in Action》一书时,我们聚焦于Hadoop生态系统中的关键技术和概念,这些技术对于理解和掌握大数据处理至关重要。...
第四章至第六章详细介绍了如何编写基本的MapReduce程序,以及高级MapReduce程序的设计与实现。书中通过多个实例演示了如何进行数据处理和分析,涵盖了诸如文本处理、数据排序、连接操作等多种常见应用场景。此外,还...
第四部分“DATASCIENCE”(数据科学)探讨了利用数据结构和算法,将R语言与Hadoop集成用于统计分析,以及使用Mahout进行预测分析。 本书的附录提供了诸如书籍信息、出版商联系信息、折扣政策、纸张的环保性说明等...
- **第4章:Making recommendations** - 经过前面几章的基础铺垫之后,本章重点介绍如何使用Mahout来实现具体的推荐算法。这包括基于内容的推荐、协同过滤等技术,并提供了丰富的代码示例帮助读者理解并实践。 - **...
第四章提供了MapReduce编程的基础知识,包括如何编写基本的MapReduce程序。 - **Map函数**:接收输入键值对,处理后输出中间键值对。 - **Reduce函数**:接收来自所有Map任务的中间键值对,进行汇总处理后输出最终...
《Hadoop_in_Action》和后续的开发者指南,如hadoop-developer-4.pdf、hadoop开发者第二期发布版v3.pdf和hadoop开发者第三期.pdf,都是为了帮助开发者持续跟踪Hadoop的发展,提供了最新的技术和最佳实践,涵盖了...
- **第2章:引荐系统的介绍**(Introducing recommenders):介绍了推荐系统的概念、应用场景及其在商业领域的价值。同时探讨了不同类型的推荐算法,如基于内容的推荐、基于协作的推荐等。 - **第3章:表示推荐数据*...