【Nutch】InjectorJob

源码分析

package org.apache.nutch.crawl;

首先呢,InjectorJob类存在于包org.apache.nutch.crawl内。

public class InjectorJob extends NutchTool implements Tool

它扩展了NutchTool类并实现了Tool类。并实现了NutchTool类的run(Map<String, Object>)方法和Tool类的run(String[])方法,Tool类即Hadoop util中的Tool类。没啥好说的。

接着呢,我们来看一看它的Mapper类和reducer类。

  public static class UrlMapper extends
      Mapper<LongWritable, Text, String, WebPage> {
    private URLNormalizers urlNormalizers;
    private int interval;
    private float scoreInjected;
    private URLFilters filters;
    private ScoringFilters scfilters;
    private long curTime;

    @Override
    protected void setup(Context context) throws IOException,
        InterruptedException {
    	/**
    	 * 一些准备工作。很多默认配置都在nutch根目录下conf文件夹中的nutch-default.xml中。
    	 */
      urlNormalizers = new URLNormalizers(context.getConfiguration(),
          URLNormalizers.SCOPE_INJECT);								/**规范化Url*/
      interval = context.getConfiguration().getInt("db.fetch.interval.default",
          2592000);													/**两次抓取同一个页面之间的默认时间间隔,30天。*/
      filters = new URLFilters(context.getConfiguration());			/**过滤不合法的Url*/
      scfilters = new ScoringFilters(context.getConfiguration());	/**一个计算分值的类*/
      scoreInjected = context.getConfiguration().getFloat("db.score.injected",
          1.0f);													/**被injector增加的新页面的分值(score)*/
      curTime = context.getConfiguration().getLong("injector.current.time",
          System.currentTimeMillis());								/**注入(inject)的时间*/
    }

    protected void map(LongWritable key, Text value, Context context)
        throws IOException, InterruptedException {
      String url = value.toString().trim(); // value is line of text

      if (url != null && (url.length() == 0 || url.startsWith("#"))) {
        /* Ignore line that start with # */
        return;
      }

      // if tabs : metadata that could be stored
      // must be name=value and separated by \t
      float customScore = -1f;
      int customInterval = interval;
      Map<String, String> metadata = new TreeMap<String, String>();	/**用来映射元数据的name和value值*/
      if (url.indexOf("\t") != -1) {
        String[] splits = url.split("\t");
        url = splits[0];
        for (int s = 1; s < splits.length; s++) {					/**对于每一个被split的name value值*/
          // find separation between name and value
          int indexEquals = splits[s].indexOf("=");
          if (indexEquals == -1) {
            // skip anything without a =
            continue;
          }
          String metaname = splits[s].substring(0, indexEquals);
          String metavalue = splits[s].substring(indexEquals + 1);
          /**
           *   对于一个特定Url,用户自定义的分值
           *   public static String nutchScoreMDName = "nutch.score";
           */
      
          if (metaname.equals(nutchScoreMDName)) {
            try {
              customScore = Float.parseFloat(metavalue);
            } catch (NumberFormatException nfe) {
            }
          }
          /**
           *  对于一个特定Url,用户自定义的抓取间隔
  		   *  public static String nutchFetchIntervalMDName = "nutch.fetchInterval";
           */
          else if (metaname.equals(nutchFetchIntervalMDName)) {
            try {
              customInterval = Integer.parseInt(metavalue);
            } catch (NumberFormatException nfe) {
            }
          } else
            metadata.put(metaname, metavalue);
        }
      }
      try {
    	  /**
    	   * 这里就是核心的规范化和过滤Url的过程了
    	   */
        url = urlNormalizers.normalize(url, URLNormalizers.SCOPE_INJECT);
        url = filters.filter(url); // filter the url
      } catch (Exception e) {
        url = null;
      }
      if (url == null) {
        context.getCounter("injector", "urls_filtered").increment(1);	/**被过滤掉的Url数目加一*/
        return;
      } else { // if it passes
    	  /**
    	   * 如果Url通过,则将从该Url中所获取的信息连同其他信息一同封装于WebPage类中用于保存。
    	   */
        String reversedUrl = TableUtil.reverseUrl(url); // collect it
        WebPage row = WebPage.newBuilder().build();
        row.setFetchTime(curTime);
        row.setFetchInterval(customInterval);

        // now add the metadata
        Iterator<String> keysIter = metadata.keySet().iterator();
        while (keysIter.hasNext()) {
          String keymd = keysIter.next();
          String valuemd = metadata.get(keymd);
          row.getMetadata().put(new Utf8(keymd),
              ByteBuffer.wrap(valuemd.getBytes()));
        }

        if (customScore != -1)
          row.setScore(customScore);
        else
          row.setScore(scoreInjected);

        try {
        	/**
        	 *  当注入新页面的时候,计算出一个新的初始值
        	 */
          scfilters.injectedScore(url, row);
        } catch (ScoringFilterException e) {
          }
        }
        context.getCounter("injector", "urls_injected").increment(1);	/**已注入Url数目加一*/
        row.getMarkers()
            .put(DbUpdaterJob.DISTANCE, new Utf8(String.valueOf(0)));
        Mark.INJECT_MARK.putMark(row, YES_STRING);
        /**
         * Mapper的输出:<String(reversedUrl), WebPage(row)>
         */
        context.write(reversedUrl, row);
      }
    }
  }

首先呢,细心的同学已经发现在存储的时候它已经将Url通过调用

String reversedUrl = TableUtil.reverseUrl(url);

变成reversedUrl了。

这是为了反转一个Url的域名,从而方便于在HBase中的存储。因为在同一域名内的扫描能更快一些。举个自带的例子:

"http://bar.foo.com:8983/to/index.html?a=b" 变成了
"com.foo.bar:8983:http/to/index.html?a=b"

然后呢,在成员变量里还出现了三个比较陌生的类:URLNormalizers, URLFilters, ScoringFilters.

这三个类呢,其实都是Nucth插件的接口。稍后我们将会另起一篇文章,利用URLNormalizers或者URLFilters类专门来说一说Nutch的插件机制。

这里先简单说一说ScoringFilters类吧,因为大家可能被我注释中页面的“分值(score)”这个说法弄晕了。比如当你没有设置conf/nutch-default.xml中的scoring.filter.order属性值,那么程序就会默认调用src/plugin中自带的scoring-opic插件,用其中的org.apache.nutch.scoring.opic.OPICScoringFilter类作为ScoringFilter类的实现。这其实就是Nutch内部的页面评分机制OPIC算法的调用,即Online Page Importance Computation算法。它实现的参考文献是这一篇论文:Adaptive On-Line Page Importance Computation.

那它是个Filter也就不难理解了,它会将页面中那些评分过低的过滤掉。

URLNormalizers类默认调用插件urlnormalizer-(pass|regex|basic).而什么是将Url规范化呢?举个例子:

urlnormalizer-basic就是用来——

remove dot segments in path:  /./ or /../
remove default ports, e.g. 80 for protocol http://

URLFilters类默认调用插件urlfilter-regex. 而Nutch自带五种过滤插件,分别为:DomainURLFilter, RegexURLFilter, AutomatonURLFilter , PrefixURLFilter, SuffixURLFilter. 这5中过滤器的配置过滤规则的文件分别为:domain-urlfilter.txt、regex-urlfilter.txt、automaton-urlfilter.txt、prefix-urlfilter.txt、suffix-urlfilter.txt。过滤器和过滤规则文件之间的关系同样是通过来nutch-default.xml来定义的。属性urlfilter.order则定义了过滤器的应用顺序,所有过滤器都是与的关系。

接下来,我们看看它的Job。

    currentJob = new NutchJob(getConf(), "inject " + input);	/**NutchJob是对Hadoop Job的一个扩展*/
    FileInputFormat.addInputPath(currentJob, input);
    currentJob.setMapperClass(UrlMapper.class);
    currentJob.setMapOutputKeyClass(String.class);
    currentJob.setMapOutputValueClass(WebPage.class);
    currentJob.setOutputFormatClass(GoraOutputFormat.class);

    DataStore<String, WebPage> store = StorageUtils.createWebStore(
        currentJob.getConfiguration(), String.class, WebPage.class);
    GoraOutputFormat.setOutput(currentJob, store, true);

    currentJob.setReducerClass(Reducer.class);
    currentJob.setNumReduceTasks(0);							/**这里可以看出这个Job根本就没有用到Reducer*/

    currentJob.waitForCompletion(true);							/**run job.*/

由于 此Job没有reduce阶段,结合上面的代码,显然可以看出输出被写入到了Gora的dataStore中。

总结一下,InjectJob就是从input中读入种子Urls,然后对其进行规范化,过滤,再进行评分。最后进行存储。


实战演练

seed.txt

http://nutch.apache.org/	nutch.score=0.172	nutch.fetchInterval=3600
result:

http://nutch.apache.org/	key:	org.apache.nutch:http/
baseUrl:	null
status:	0 (null)
fetchTime:	1440072184529
prevFetchTime:	0
fetchInterval:	3600
retriesSinceFetch:	0
modifiedTime:	0
prevModifiedTime:	0
protocolStatus:	(null)
parseStatus:	(null)
title:	null
score:	0.172
marker _injmrk_ : 	y
marker dist : 	0
reprUrl:	null
metadata _csh_ : 	>0 �

   
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本火锅店点餐系统采用Java语言和Vue技术,框架采用SSM,搭配Mysql数据库,运行在Idea里,采用小程序模式。本火锅店点餐系统提供管理员、用户两种角色的服务。总的功能包括菜品的查询、菜品的购买、餐桌预定和订单管理。本系统可以帮助管理员更新菜品信息和管理订单信息,帮助用户实现在线的点餐方式,并可以实现餐桌预定。本系统采用成熟技术开发可以完成点餐管理的相关工作。 本系统的功能围绕用户、管理员两种权限设计。根据不同权限的不同需求设计出更符合用户要求的功能。本系统中管理员主要负责审核管理用户,发布分享新的菜品,审核用户的订餐信息和餐桌预定信息等,用户可以对需要的菜品进行购买、预定餐桌等。用户可以管理个人资料、查询菜品、在线点餐和预定餐桌、管理订单等,用户的个人资料是由管理员添加用户资料时产生,用户的订单内容由用户在购买菜品时产生,用户预定信息由用户在预定餐桌操作时产生。 本系统的功能设计为管理员、用户两部分。管理员为菜品管理、菜品分类管理、用户管理、订单管理等,用户的功能为查询菜品,在线点餐、预定餐桌、管理个人信息等。 管理员负责用户信息的删除和管理,用户的姓名和手机号都可以由管理员在此功能里看到。管理员可以对菜品的信息进行管理、审核。本功能可以实现菜品的定时更新和审核管理。本功能包括查询餐桌,也可以发布新的餐桌信息。管理员可以查询已预定的餐桌,并进行审核。管理员可以管理公告和系统的轮播图,可以安排活动。管理员可以对个人的资料进行修改和管理,管理员还可以在本功能里修改密码。管理员可以查询用户的订单,并完成菜品的安排。 当用户登录进系统后可以修改自己的资料,可以使自己信息的保持正确性。还可以修改密码。用户可以浏览所有的菜品,可以查看详细的菜品内容,也可以进行菜品的点餐。在本功能里用户可以进行点餐。用户可以浏览没有预定出去的餐桌,选择合适的餐桌可以进行预定。用户可以管理购物车里的菜品。用户可以管理自己的订单,在订单管理界面里也可以进行查询操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值