接下来的代码是:
// read the subdirectories generated in the temp
// output and turn them into segments
List<Path> generatedSegments = new ArrayList<Path>();
FileStatus[] status = fs.listStatus(tempDir); //获取文件夹的文件列表
try
{
for (FileStatus stat : status) { //对于每一个文件
Path subfetchlist = stat.getPath(); //获取路径
if (!subfetchlist.getName().startsWith("fetchlist-")) //判断是否以fetchlist开头...
continue;
// start a new partition job for this segment
Path newSeg = partitionSegment(fs, segments, subfetchlist, numLists); //又开启了一个Hadoop任务。
generatedSegments.add(newSeg);
}
}
catch (Exception e)
{
LOG.warn("Generator: exception while partitioning segments, exiting ...");
fs.delete(tempDir, true);
return null;
}
-------------------接下来看看Hadoop任务如何执行的。
先看代码:
// invert again, partition by host/domain/IP, sort by url hash
if (LOG.isInfoEnabled()) {
LOG.info("Generator: Partitioning selected urls for politeness.");
}
Path segment = new Path(segmentsDir, generateSegmentName());
Path output = new Path(segment, CrawlDatum.GENERATE_DIR_NAME);
LOG.info("Generator: segment: " + segment);
NutchJob job = new NutchJob(getConf());
job.setJobName("generate: partition " + segment);
job.setInt("partition.url.seed", new Random().nextInt());
FileInputFormat.addInputPath(job, inputDir);
job.setInputFormat(SequenceFileInputFormat.class);
job.setMapperClass(SelectorInverseMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(SelectorEntry.class);
job.setPartitionerClass(URLPartitioner.class);
job.setReducerClass(PartitionReducer.class);
job.setNumReduceTasks(numLists);
FileOutputFormat.setOutputPath(job, output);
job.setOutputFormat(SequenceFileOutputFormat.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(CrawlDatum.class);
job.setOutputKeyComparatorClass(HashComparator.class);
JobClient.runJob(job);
return segment;
从中可以看到,这个Hadoop任何的核心还是map类,reduce类。
下面一一进行解释。
------------------------------------------------------
job.setMapperClass(SelectorInverseMapper.class);
进入这个类的代码。
这个类的代码真的是叫送福利来了,为啥,因为太简单了。
public static class SelectorInverseMapper extends MapReduceBase implements
Mapper<FloatWritable, SelectorEntry, Text, SelectorEntry> {
public void map(FloatWritable key, SelectorEntry value,
OutputCollector<Text, SelectorEntry> output, Reporter reporter)
throws IOException {
SelectorEntry entry = value;
output.collect(entry.url, entry);
}
}
很简单,但是这里需要提醒的是,这里的参数FloatWritable key被丢弃了?
为什么?
说明这里不需要了,那么这里的key怎么回事?实际上这里的key是之前的分数。
分数在这里被丢弃,不需要了,说明上一篇文章做了一个分数排序优先级的概念。
看到这里,我也才明白上一篇文章的精髓之所在。醍醐灌顶。
---------------------------------------------------------------
接下来是Partition分区操作。
job.setPartitionerClass(URLPartitioner.class);
这里的操作跟上一篇的操作时一样的,所以这里也不赘述。
---------------------------------------------------------------
接下来讲解reduce类。
job.setReducerClass(PartitionReducer.class);
看一看它的代码。仍然是送福利,太爽了。
public static class PartitionReducer extends MapReduceBase implements
Reducer<Text, SelectorEntry, Text, CrawlDatum> {
public void reduce(Text key, Iterator<SelectorEntry> values,
OutputCollector<Text, CrawlDatum> output, Reporter reporter)
throws IOException {
// if using HashComparator, we get only one input key in case of
// hash collision
// so use only URLs from values
while (values.hasNext()) {
SelectorEntry entry = values.next();
output.collect(entry.url, entry.datum);
}
}
}
这是最容易搞定的代码!
---------------------------------然后,接下来是数据校验
if (generatedSegments.size() == 0) {
LOG.warn("Generator: 0 records selected for fetching, exiting ...");
LockUtil.removeLockFile(fs, lock);
fs.delete(tempDir, true);
return null;
}
这段代码很简单,就不赘述了。
------------------------------------------------------
接下来的代码:
if (getConf().getBoolean(GENERATE_UPDATE_CRAWLDB, false)) {
这段默认值是false.所以下面的代码暂时不执行,但是应该可以作为【提高效率】的一个点。
后续 有时间再分析这段代码。
---------------------------------------------------------------------------------
接下来的代码是:
long end = System.currentTimeMillis();
LOG.info("Generator: finished at " + sdf.format(end) + ", elapsed: "
+ TimingUtil.elapsedTime(start, end));
Path[] patharray = new Path[generatedSegments.size()];
return generatedSegments.toArray(patharray);
返回最终结果,里面是segments的路径。
至此,generate分析完毕!