1、.equals(argsi) 3. dir = new Path(argsi+1);4. i+;5. else if (-threads6. threads = Integer. parseInt(argsi+1);7. i+;8. else if (-depth9. depth = Integer. parseInt(argsi+1);10. i+;11. else if (-topN12. topN = Integer. parseInt(argsi+1);13. i+;14. else if (-solr15. indexerName = solr;16. solrUrl = Strin
2、gUtils. lowerCase(argsi + 1);17. i+;18. else if (argsi != null) 19. rootUrlDir = new Path(argsi);20. 21. 下面就开始进入正题了:1. 首先调用Injector的inject函数将rootUrlDir目录下的所有文件中的网址注入到crawlDb数据库。2. 根据指定的抓取深度,循环做以下三件事: 调用Generator的generate函数,产生URL的fetchlist,并放在一个或者多个segments中。 调用Fetcher的fetch函数,获取segs0所制定的segement,并Pa
3、rsing,parsing操作可以是集成在了fetch这一步,也可以是单独下一步来做。这儿值得注意的是,只取了第一个seg,而数组中有可能有多个seg,没有fetch。 调用CrawlDb的update函数,将segments中的fetch和parsing的数据合并到数据库(crawlDb)中。这里取的是segs数组,我觉得这儿可能是有问题的。3. 建立并合并索引。1. / initialize crawlDb 2. injector.inject(crawlDb, rootUrlDir);3. int i;4. for (i = 0; depth; i+) / generate new se
4、gment 5. Path segs = generator.generate(crawlDb, segments, -1, topN, System 6. . currentTimeMillis();7. if (segs = null) 8. LOG.info(Stopping at depth= + i + - no more URLs to fetch.);9. break;10. 11. fetcher.fetch(segs0, threads, org.apache.nutch.fetcher.Fetcher. isParsing(conf); / fetch it 12. if
5、(!Fetcher.isParsing(job) 13. parseSegment.parse(segs0); / parse it, if needed 14. 15. crawlDbTool.update(crawlDb, segs, true, true); / update crawldb 16. 17. if (i 0) 18. linkDbTool.invert(linkDb, segments, true, true, false); / invert links 19. / index, dedup & merge 20. FileStatus fstats = fs.list
6、Status(segments, HadoopFSUtil.getPassDirectoriesFilter(fs);21. if (isSolrIndex) 22. SolrIndexer indexer = new SolrIndexer(conf);23. indexer.indexSolr(solrUrl, crawlDb, linkDb, 24. Arrays. asList(HadoopFSUtil.getPaths (fstats);25. 26. else 27. 28. DeleteDuplicates dedup = new DeleteDuplicates(conf);2
7、9. if(indexes !30. / Delete old indexes 31. if (fs.exists(indexes) 32. LOG.info( Deleting old indexes: + indexes);33. fs.delete(indexes, true);34. 35. / Delete old index 36. if (fs.exists(index) 37. LOG.info( Deleting old merged index: + index);38. fs.delete(index, true);39. 40. 41. 42. Indexer inde
8、xer = new Indexer(conf);43. indexer.index(indexes, crawlDb, linkDb, 44. Arrays. asList(HadoopFSUtil.getPaths (fstats);45. 46. IndexMerger merger = new IndexMerger(conf);47. if(indexes !48. dedup.dedup( new Path indexes );49. fstats = fs.listStatus(indexes, HadoopFSUtil. getPassDirectoriesFilter(fs);
9、50. merger.merge(HadoopFSUtil. getPaths(fstats), index, tmpDir);51. 52. 53. 54. else 55. LOG.warn(No URLs to fetch - check your seed list and URL filters.56. 57. if (LOG.isInfoEnabled() LOG.info( crawl finished: + dir); Nutch源代码浅析(二)(Crawl中Inject的工作流程)Inject操作的入口函数在org.apache.nutch.crawl.Injector中,m
10、ain函数调用run函数,最后进入inject函数:1、产生一个以随机数结尾的文件夹tempDir。2、运行一个Hadoop的MapRed JOb(sortJob),将urls目录下的所有网址读出,并保存到3、OutputCollector对象中,而后将该对象序列化到tempDir文件夹下。3、运行另外一个Hadoop的MapRed Job(mergeJob),将tempDir新产生数据和crawlDb已有的老数据合并,合并过程如果有某些网址新旧冲突,将保留已有的老数据,最终结果将保存于crawlDb下的一个随机数命名的文件夹newCrawlDb中(有别于1中的名称)。4、重命名crawlDb
11、下的“current”文件夹为“old”,如果“old”文件夹已经存在,将删除之,而后将newCrawlDb文件夹重名为current,删除tempDir。public void inject(Path crawlDb, Path urlDir) throws IOException SimpleDateFormat sdf = new SimpleDateFormat(yyyy-MM-dd HH:mm:ss long start = System.currentTimeMillis(); if (LOG.isInfoEnabled() LOG.info(Injector: starting
12、at + sdf.format(start); crawlDb: + crawlDb); urlDir: + urlDir); / 默认会在当前文件夹产生类似于inject-temp-853856658的目录,数位为随机数 Path tempDir = new Path(getConf().get(mapred.temp.dir, .) + /inject-temp-+ Integer.toString(new Random().nextInt(Integer.MAX_VALUE); / map text input file to a file Converting injected url
13、s to crawl db entries. JobConf sortJob = new NutchJob(getConf(); sortJob.setJobName(inject / 讲命令行中传入的urls目录作为sortJob的输入,其后将会读取其中的内容 FileInputFormat.addInputPath(sortJob, urlDir); / InjectMapper会根据urls目录下所有文件的内容,产生OutputCollector对象。 / 其中Text表示url,而CrawlDatum对象则存放着url相关的状态信息,稍后会详加介绍。 / 有两种方法设置Mapper,一
14、中通过setMapperClass,另一种通过setMapRunnerClass,后法在Fetcher中有使用, / 优点可以以线程启动 sortJob.setMapperClass(InjectMapper.class); / 将输出的结构存放的tempDir目录下 FileOutputFormat.setOutputPath(sortJob, tempDir); / 采用Sequence的方式存储文件 sortJob.setOutputFormat(SequenceFileOutputFormat.class); / 设置Key和Value的Class,和InjectMapper的map输
15、出OutputCollector相对应的 / 对所有Hadoop中的Job都必须符合这一规则。 sortJob.setOutputKeyClass(Text.class); sortJob.setOutputValueClass(CrawlDatum.class); sortJob.setLong(injector.current.time, System.currentTimeMillis(); / 调用Hadoop中的MapRed实现,运行sortJob JobClient.runJob(sortJob); / merge with existing crawl db Merging in
16、jected urls into crawl db. / 将根据urls目录下产生的临时数据tempDir合并到crawlDb已有的数据中 / mergeJob的具体设置在CrawlDb.createJob()中实现 JobConf mergeJob = CrawlDb.createJob(getConf(), crawlDb); FileInputFormat.addInputPath(mergeJob, tempDir); / 调用InjectReducer中的reduce函数,实现合并 mergeJob.setReducerClass(InjectReducer.class); JobC
17、lient.runJob(mergeJob); / 备份crawlDb中的老数据,将新的结果替换为新的数据 CrawlDb.install(mergeJob, crawlDb); / clean up / 清楚中间数据 FileSystem fs = FileSystem.get(getConf(); fs.delete(tempDir, true); long end = System.currentTimeMillis(); finished at + sdf.format(end) + , elapsed: + TimingUtil.elapsedTime(start, end); 而后
18、我们来看看InjectMapper是如何实现map操作的,会发现,起始url可以有两个参数,并且在此函数中引入了urlfilter和scorefilter/ key在此没用到,而value中这是从urls文件下文件中读出的一行字符串 / 输出会追加到output中,Text是url,而CrawlDatum为该url想对应的状态等信息 public void map(WritableComparable key, Text value, OutputCollector output, Reporter reporter) throws IOException String url = value
19、.toString(); / value is line of text if (url != null & url.trim().startsWith(#) /* Ignore line that start with # */ return; / 在url文件中描述一个url时,需要以其网址开头,需要以tab键隔开, / 目前支持在其后追加两种参数(可同时存在),nutch.score和nutch.fetchInterval, / 这样我们可以根据需要对某个url单独设置score和fetchInterval, / 这两个参数将会作为metadata存入CrawlDatum对象中 / if
20、 tabs : metadata that could be stored / must be name=value and separated by /t float customScore = -1f; int customInterval = interval; Map metadata = new TreeMap(); if (url.indexOf(/t)!=-1) String splits = url.split( url = splits0; for (int s=1;ssplits.length;s+) / find separation between name and v
21、alue int indexEquals = splitss.indexOf(= if (indexEquals=-1) / skip anything without a = continue; String metaname = splitss.substring(0, indexEquals); String metavalue = splitss.substring(indexEquals+1); if (metaname.equals(nutchScoreMDName) try customScore = Float.parseFloat(metavalue); catch (Num
22、berFormatException nfe) else if (metaname.equals(nutchFetchIntervalMDName) customInterval = Integer.parseInt(metavalue); else metadata.put(metaname,metavalue); url = urlNormalizers.normalize(url, URLNormalizers.SCOPE_INJECT); / 注意,这就是urlfilter的入口点,在inject到crawlDb之前需要经历urlfilter的筛选, / 如果不符合筛选条件,将返回nu
23、ll,对此url将不做后续的工作 url = filters.filter(url); / filter the url catch (Exception e) if (LOG.isWarnEnabled() LOG.warn(Skipping +url+:+e); url = null;= null) / if it passes value.set(url); / collect it CrawlDatum datum = new CrawlDatum(CrawlDatum.STATUS_INJECTED, customInterval); datum.setFetchTime(curTi
24、me); / now add the metadata Iterator keysIter = metadata.keySet().iterator(); while (keysIter.hasNext() String keymd = keysIter.next(); String valuemd = metadata.get(keymd); datum.getMetaData().put(new Text(keymd), new Text(valuemd); if (customScore != -1) datum.setScore(customScore); else datum.set
25、Score(scoreInjected); / 注意,这儿是score filter的入口点 scfilters.injectedScore(value, datum); catch (ScoringFilterException e) if (LOG.isWarnEnabled() LOG.warn(Cannot filter injected score for url + url + , using default ( + e.getMessage() + ) / 将结果添加到output中 output.collect(value, datum);再看看InjectReducer是如何实现reduce的,简而言之,新旧合并,新旧冲突时,保留老的/ reduce顾名思义就是了处理一对多的情况,为了处理新老之间的合并而已, / 所以从函数的入参可以看出一些端倪,一个key,但一组values,输出依然是 / OutputCollectorpublic void reduce(Text key, Itera
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1