<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    我的家園

    我的家園

    Nutch 源代碼分析(1) Crawl 類

    Posted on 2012-04-15 16:27 zljpp 閱讀(319) 評論(0)  編輯  收藏
     ?。ㄒ韵路治鲠槍Φ氖?nutch 1.4)

      Crawl 類是運行抓取程序的入口,代碼不多,但關聯的其他類不少。
      抓取的流程是:

      1. 將初始的 URL 地址注入到 crawlDb

      2. 從crawldb中生成一個url的子集用于抓取
      3. 抓取網頁
      4. 分析網頁
      5. 更新 crawlDb ,增加新抓取的 url

      6. 循環執行 2-5 步,直到達到指定的抓取深度

      之后,還需要進行鏈接反轉,將索引導入到 solr 等。

      Crawl 類的聲明如下:
    public class Crawl extends Configured implements Tool
    

      Configured 和 Tool 是 hadoop 中的概念
      Configured 是 hadoop 中用來提供配置信息的,在 ToolRunner.run 方法中,會將創建好的 Configuration 對象通過 Configured.setConf 方法注入到 Crawl 中。
      Tool 是 hadoop 中用來處理命令行參數并修改 Map-Reduce 任務的參數,它需要在 run 方法中處理這些命令行參數。

      因為 Crawl 實現了 Tool 接口,我們可以通過命令行啟動數據抓取的 Map-Reduce 任務。
      啟動 Crawl 的 main 方法如下:
      public static void main(String args[]) throws Exception {
        // 創建 Configuration  對象
        Configuration conf = NutchConfiguration.create();
    
        // 執行任務
        int res = ToolRunner.run(conf, new Crawl(), args);
    
        // 退出程序
        System.exit(res);
      }
    

      NutchConfiguration.create 會加載 nutch-default.xml 和 nutch-site.xml 中的配置信息生成 Configuration  對象。
      ToolRunner.run 方法會將創建好的 Configuration 對象通過 Configured.setConf 方法注入到 Crawl 中(Crawl 繼承了Configured),并將參數的處理委托給 Tool.run 方法(Crawl 實現了 Tool 接口,因此需要提供 run 方法的實現)。
      接下來我們重點分析一下 Crawl 類的 run 方法。

      首先是參數的設置:
        // 默認參數
        Path rootUrlDir = null;
        Path dir = new Path("crawl-" + getDate());
        int threads = getConf().getInt("fetcher.threads.fetch", 10);
        int depth = 5;
        long topN = Long.MAX_VALUE;
        String solrUrl = null;
    

      這幾個參數的含義如下:

      rootUrlDir : 要抓取的起始 url 所在的目錄
      dir : 默認情況下,抓取時生成的文件的目錄
      threads : 抓取數據的線程數
      depth : 通過外鏈抓取網頁的深度,從起始 url 算起
      topN : 每輪抓取獲得的新的 url 中,只對分值最高的 topN 個 url 再次抓取
      solrUrl : solr 的地址。用于調用 solr 的 api 建立用于搜索的索引。


      這些參數是可以根據命令行的輸入修改的:
        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 ("-solr".equals(args[i])) {
            solrUrl = StringUtils.lowerCase(args[i + 1]);
            i++;
          } else if (args[i] != null) {
            rootUrlDir = new Path(args[i]);
          }
        }
    


      然后需要創建抓取程序將要用到的對象:
        Path tmpDir = job.getLocalPath("crawl"+Path.SEPARATOR+getDate());
        Injector injector = new Injector(getConf());
        Generator generator = new Generator(getConf());
        Fetcher fetcher = new Fetcher(getConf());
        ParseSegment parseSegment = new ParseSegment(getConf());
        CrawlDb crawlDbTool = new CrawlDb(getConf());
        LinkDb linkDbTool = new LinkDb(getConf());
    

      這里簡要說明一下這些對象的作用:
      injector : 將初始的 URL 地址到 crawlDb
      generator : 生成要抓取的 URL
      fetcher : 抓取網頁
      parseSegment : 分析網頁
      crawlDbTool : CrawlDb 類的實例,存放將要抓取的 URL
      linkDbTool : 用于存放鏈接之間的引用關系,便于計算權重


      完成以上的準備工作之后,就開始執行主要的處理邏輯:
        // 初始化 crawlDb
        // 將初始的 URL 地址到 crawlDb 
        injector.inject(crawlDb, rootUrlDir);
    
        int i;
    
        // 循環執行,直到達到指定的抓取深度
        for (i = 0; i < depth; i++) {
          // 生成要抓取的 URL 
          Path[] segs = generator.generate(crawlDb, segments, -1, topN, System.currentTimeMillis());
    
          // 沒有需要抓取的 URL 了,提前中止抓取過程
          if (segs == null) {
            LOG.info("Stopping at depth=" + i + " - no more URLs to fetch.");
            break;
          }
    
          fetcher.fetch(segs[0], threads);  // 抓取網頁
    
          if (!Fetcher.isParsing(job)) {
            parseSegment.parse(segs[0]);    // 分析網頁
          }
          crawlDbTool.update(crawlDb, segs, true, true); // 更新 crawldb,增加需要抓取的 URL
        }
    

      前面通過抓取和分析網頁得到的鏈接格式為 源鏈接 => 目標鏈接,
      需要通過反轉,得到目標鏈接對應的源鏈接,以便于計算目標鏈接的權重等:
      linkDbTool.invert(linkDb, segments, true, true, false);
    

      最后,如果指定了 solrUrl,需要將 nutch 索引導入到 solr 中
          // 將索引導入到 solr
          if (solrUrl != null) {
    
            // 獲取創建好的 nutch 索引的文件索引
            FileStatus[] fstats = fs.listStatus(segments, HadoopFSUtil.getPassDirectoriesFilter(fs));
    
            // 建立 Solr 索引
            SolrIndexer indexer = new SolrIndexer(getConf());
            indexer.indexSolr(solrUrl, crawlDb, linkDb,  Arrays.asList(HadoopFSUtil.getPaths(fstats)));
    
            // 去重
            SolrDeleteDuplicates dedup = new SolrDeleteDuplicates();
            dedup.setConf(getConf());
            dedup.dedup(solrUrl);
          }
    


      以上只是對源代碼進行字面上的分析,更深入的分析可以參考以下文章:
      http://blog.csdn.net/kauu/article/details/1823830
      http://www.diybl.com/course/3_program/java/javajs/20100719/459450.html




    只有注冊用戶登錄后才能發表評論。


    網站導航:
    博客園   IT新聞   Chat2DB   C++博客   博問  
     
    主站蜘蛛池模板: 夜夜爽免费888视频| 国产大片免费网站不卡美女| 国产无遮挡吃胸膜奶免费看| 亚洲日本一线产区和二线| 无码国产精品一区二区免费式直播 | 国产大片线上免费看| 2020天堂在线亚洲精品专区| 黄瓜视频高清在线看免费下载| 亚洲AV无码成人精品区在线观看| 国产在线精品免费aaa片| 亚洲综合自拍成人| 亚洲国产精品免费视频| 噜噜噜亚洲色成人网站∨| 久久免费看黄a级毛片| 亚洲剧情在线观看| 日韩成人免费视频播放| 国产成人精品久久亚洲高清不卡 | 亚洲成A人片77777国产| 在线播放国产不卡免费视频| 亚洲国产精品无码av| 美女内射无套日韩免费播放| 亚洲一卡2卡3卡4卡乱码 在线| 日韩精品免费电影| 一级一看免费完整版毛片| 日韩亚洲一区二区三区| 亚洲免费中文字幕| 激情小说亚洲色图| 亚洲色大成网站www永久一区| 99在线视频免费| 亚洲色丰满少妇高潮18p| 又大又粗又爽a级毛片免费看| 国产一级a毛一级a看免费视频| 久久亚洲精品成人无码网站| 国产青草视频免费观看97| 岛国岛国免费V片在线观看| 亚洲电影在线免费观看| 免费欧洲美女牲交视频| 无码av免费网站| 黄色网址在线免费观看| 亚洲国产成人久久精品动漫 | 红杏亚洲影院一区二区三区|