大家好,今天我们在Hadoop 实战之分析专利引用数据集(一)的基础上来实现计算专利被引用的次数
许多外行人认为统计学就是数量统计,并且许多基本的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程序的结构。
在运行之前的例子之后,我们现在有了统计每个专利被引用的次数的数据。一个有趣的练习是对统计结果进行计数。我们预期大量的专利可能只会被引用一次,而少数的专利将会被引用几百次。观察引用次数的分布是一件有趣的事情。
编写MapReduce程序的第一步是弄清楚数据流。在这种情况下,mapper读取记录时,忽略了专利号,并输出中间键/值对<citation_count, 1>。reducer会将每个引用计数加1,并将总数输出。
在弄清楚数据流之后,需要决定键值对的类型——K1、V1,K2、 V2, K3和V3,分别用于输入、中间结果和输出键/值对。我们将使用KeyValueTextInputFormat类型,它将自动地将每个输入记录分解为基于分隔符的键/值对。输出格式将K1和V1作为文本进行处理。我们选择IntWritable类作为K2、V2、K3和V3的类型,因为我们知道那些数据肯定是整数,并且使用IntWritable的性能更好。
环境:Vmware 8.0 和Ubuntu11.04
Hadoop 实战之分析专利引用数据集(三)---从专利引用数据集中计算专利被引用的次数
第一步:首先创建一个工程命名为HadoopTest.目录结构如下图:
sudo rm -rf /tmp/*
rm -rf /home/tanglg1987/hadoop-0.20.2/logs
hadoop namenode -format
hadoop datanode -format
start-all.sh
hadoop fs -mkdir input
hadoop dfsadmin -safemode leave
第三步:给start.sh增加执行权限并启动hadoop伪分布式集群,代码如下:
chmod 777 /home/tanglg1987/start.sh
./start.sh
执行过程如下:
第四步:上传本地文件到hdfs
在专利局http://data.nber.org/patents/网站下载专利数据
http://data.nber.org/patents/apat63_99.zip
hadoop fs -put /home/tanglg1987/cite75_99.txt input
五步:新建一个MyJob3.java,代码如下:
package com.baison.action;
import java.io.IOException;
import java.util.Iterator;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.FileInputFormat;
import org.apache.hadoop.mapred.FileOutputFormat;
import org.apache.hadoop.mapred.JobClient;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapred.KeyValueTextInputFormat;
import org.apache.hadoop.mapred.MapReduceBase;
import org.apache.hadoop.mapred.Mapper;
import org.apache.hadoop.mapred.OutputCollector;
import org.apache.hadoop.mapred.Reducer;
import org.apache.hadoop.mapred.Reporter;
import org.apache.hadoop.mapred.TextOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
public class MyJob3 extends Configured implements Tool {
public static class MapClass extends MapReduceBase
implements Mapper<Text, Text, Text, Text> {
public void map(Text key, Text value,
OutputCollector<Text, Text> output,
Reporter reporter) throws IOException {
output.collect(value, key);
}
}
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 {
String csv = "";
int count=0;
while (values.hasNext()) {
if (csv.length() > 0) csv += ",";
csv += values.next().toString();
count++;
}
output.collect(key, new IntWritable(count));
}
}
public int run(String[] args) throws Exception {
for (String string : args) {
System.out.println(string);
}
Configuration conf = getConf();
JobConf job = new JobConf(conf, MyJob3.class);
Path in = new Path(args[0]);
Path out = new Path(args[1]);
FileInputFormat.setInputPaths(job, in);
FileOutputFormat.setOutputPath(job, out);
job.setJobName("MyJob");
job.setMapperClass(MapClass.class);
job.setReducerClass(Reduce.class);
job.setInputFormat(KeyValueTextInputFormat.class);
job.setOutputFormat(TextOutputFormat.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
job.set("key.value.separator.in.input.line", ",");
JobClient.runJob(job);
return 0;
}
public static void main(String[] args) throws Exception {
String [] arg={"hdfs://localhost:9100/user/tanglg1987/input/cite75_99.txt","hdfs://localhost:9100/user/tanglg1987/output"};
int res = ToolRunner.run(new Configuration(), new MyJob3(), arg);
System.exit(res);
}
}
第六步:Run On Hadoop,运行过程如下:
hdfs://localhost:9100/user/tanglg1987/input/cite75_99.txt
hdfs://localhost:9100/user/tanglg1987/output
12/10/18 22:24:57 INFO jvm.JvmMetrics: Initializing JVM Metrics with processName=JobTracker, sessionId=
12/10/18 22:24:57 WARN mapred.JobClient: No job jar file set. User classes may not be found. See JobConf(Class) or JobConf#setJar(String).
12/10/18 22:24:58 INFO mapred.FileInputFormat: Total input paths to process : 1
12/10/18 22:24:58 INFO mapred.JobClient: Running job: job_local_0001
12/10/18 22:24:58 INFO mapred.FileInputFormat: Total input paths to process : 1
12/10/18 22:24:58 INFO mapred.MapTask: numReduceTasks: 1
12/10/18 22:24:58 INFO mapred.MapTask: io.sort.mb = 100
12/10/18 22:24:58 INFO mapred.MapTask: data buffer = 79691776/99614720
12/10/18 22:24:58 INFO mapred.MapTask: record buffer = 262144/327680
12/10/18 22:24:59 INFO mapred.MapTask: Spilling