package org.apache.nutch.crawl
//日志产生类,其中通过调用工厂方法LogFactory.getInstance(String name)
//获取一个org.apache.commons.logging.Log实例的引用
//log类可以调用debug(),info(),warn(),error(),fatal()方法将信息记录下来
//例如:
// import org.apache.commons.logging.Log;
// import org.apache.commons.logging.LogFactory;
// public class MyClass{
// protected static Log log=LogFactory.getLog("my.component");
// //start() method called once at startup time
// public void start(){
// ...
// log.info("MyComponent started");
// ...
// }
//}
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
//hadoop是一个分布式系统基础架构,由Apache基金会开发。用户可以在不了解分布//式底层细节的情况下,开发分布式程序。充分利用集群的威力高速运算和存储。
//其中org.apache.hadoop.fs定义了抽象的文件系统API。
//org.apache.hadoop.conf定义了系统参数的配置文件处理API。
//org.apache.hadoop.mapred定义了Hadoop分布式计算系统(MapReduce)模块的实现,//包括任务的分发调度等。
//Map/Reduce最初是由google工程师设计并实现的,是一个用于大规模分步计算的的模型
//他通过用户定义一个map函数处理一个key/value以生成一批中间的key/value对。再定//义一个reduce函数将所有这些中间的key和values合并起来。
import org.apache.hadoop.fs.*;
import org.apache.hadoop.conf.*;
import org.apache.hadoop.mapred.*;
//引入nutch包,其中org.apache.nutch.parse.ParseSegment的作用是,将fetch的页面//解析为text和data,存于segments目录////下。
org.apache.nutch.indexer.DeleteDupllicaters的作用未知,猜测是删除重复的链接//,还需要进一步了解。
//org.apache.nutch.indexer.IndexMerger用于生成的索引的合并,org.apache.nutch.indexer.Indexer用于生成索引,org.apache.nutch.util.HadoopFSUtil采用hadoop的分布式
//算法,org.apache.nutch.util.NutchConfiguration的配置,org.apache.nutch.fetcher.Fetcher用于获取网页,org.apache.nutch.util.NutchJob的作用未知
import org.apache.nutch.parse.ParseSegment;
import org.apache.nutch.indexer.DeleteDuplicates;
import org.apache.nutch.indexer.IndexMerger;
import org.apache.nutch.indexer.Indexer;
import org.apache.nutch.util.HadoopFSUtil;
import org.apache.nutch.util.NutchConfiguration;
import org.apache.nutch.util.NutchJob;
import org.apache.nutch.fetcher.Fetcher;
//Crawl主类
public class Crawl {
//新建一个静态log
public static final Log LOG = LogFactory.getLog(Crawl.class);
//getDate方法用于标定抓取搜素的时间,后面将用getDate的结果来定义抓取文件所存放的
//文件夹名
private static String getDate() {
return new SimpleDateFormat("yyyyMMddHHmmss").format
(new Date(System.currentTimeMillis()));
}
//说明Crawl类的用法
if (args.length < 1) {
System.out.println
("Usage: Crawl <urlDir> [-dir d] [-threads n] [-depth i] [-topN N]");
return;
}
//建立一个抓取的配置文件,配置文件来自于crawl-tool.xml文件
Configuration conf = NutchConfiguration.create();
conf.addResource("crawl-tool.xml");
//NutchJob表明一次Nutch工作或者过程
JobConf job = new NutchJob(conf);
//定义存放抓取结果的目标路径
Path rootUrlDir = null;
Path dir = new Path("crawl-" + getDate());
// job.getIn中的10代表Threads同时运行的线程数
int threads = job.getInt("fetcher.threads.fetch", 10);
int depth = 5;//搜素深度
long topN = Long.MAX_VALUE;
//通过参数定义dir、threads、depth、topN四个参数
//所用的方法是参数表的遍历
for (int i = 0; i < args.length; i++) {
if ("-dir".equals(args[i])) {
dir = new Path(args[i+1]);
i++;
} else if ("-threads".equals(args[i])) {
threads = Integer.parseInt(args[i+1]);
i++;
} else if ("-depth".equals(args[i])) {
depth = Integer.parseInt(args[i+1]);
i++;
} else if ("-topN".equals(args[i])) {
topN = Integer.parseInt(args[i+1]);
i++;
} else if (args[i] != null) {
rootUrlDir = new Path(args[i]);
}
}
//获得文件系统
FileSystem fs = FileSystem.get(job);
//通过Log的info()方法写入参数记录
if (LOG.isInfoEnabled()) {
LOG.info("crawl started in: " + dir);
LOG.info("rootUrlDir = " + rootUrlDir);
LOG.info("threads = " + threads);
LOG.info("depth = " + depth);
if (topN != Long.MAX_VALUE)
LOG.info("topN = " + topN);
}
//在抓取目录下设置五个文件夹(使用Path方法)
Path crawlDb = new Path(dir + "/crawldb");
Path linkDb = new Path(dir + "/linkdb");
Path segments = new Path(dir + "/segments");
Path indexes = new Path(dir + "/indexes");
Path index = new Path(dir + "/index");
//设置抓取的临时文件夹,在生成索引后,就没有需要了
Path tmpDir = job.getLocalPath("crawl"+Path.SEPARATOR+getDate());
for (int i = 0; i < depth; i++) { // generate new segment
Path segment = //新建segment里面的一个文件夹
new Generator(job).generate(crawlDb, segments, -1,
topN, System.currentTimeMillis()); //
new Fetcher(job).fetch(segment, threads); // fetch it //抓取
if (!Fetcher.isParsing(job)) {
new ParseSegment(job).parse(segment); // parse it, if needed //如果没有剖析过,剖析该Segment
}
new CrawlDb(job).update(crawlDb, segment); // update crawldb //更新crawl,应该是加入新剖析的Segment
}
new LinkDb(job).invert(linkDb, segments); // invert links //将Segments中的信息加入到linkDb中
// index, dedup & merge生成索引,去除相同链接结果,合并索引(nutch生成一个索引就//好)并且将抓取成功写入日志
new Indexer(job).index(indexes, crawlDb, linkDb, fs.listPaths(segments));
new DeleteDuplicates(job).dedup(new Path[] { indexes });
new IndexMerger(fs, fs.listPaths(indexes), index, tmpDir, job).merge();
//如果需要写日志文件,将信息加入到日志文件中
if (LOG.isInfoEnabled()) { LOG.info("crawl finished: " + dir); }
}
}