nutch1.6与mongoDB的轻度结合

nutch采集后的数据,以hadoop数据结构的形式保存,不方便直观的调用,虽然有对应的读取接口,但是可读性依然较差。nutch2.0已经在整合mysql等方面有很多优异表现。不过应对大数据场景下,mysql性能实在不容乐观。最近做贝叶斯算法,数据大范围的迁移到mongoDB,于是针对nutch1.6做轻度的二次开发,将爬取下的数据另存一份到mongoDB.。当然这个是轻量级的,重量级的应该是nutch全过程的写入和存储都指向到mongoDB。

 

1,nutch网页内容的存储过程

         nutch的采集是通过Fetcher实现的。


JobConf job = new NutchJob(getConf());

  job.setJobName("fetch " + segment);

  job.setInt("fetcher.threads.fetch", threads);//设置线程数

  job.set(Nutch.SEGMENT_NAME_KEY, segment.getName());

  // for politeness, don't permit parallel execution of a single task

  job.setSpeculativeExecution(false);

  FileInputFormat.addInputPath(job, new Path(segment, CrawlDatum.GENERATE_DIR_NAME));

  job.setInputFormat(InputFormat.class);

  job.setMapRunnerClass(Fetcher.class);//设置map多线程类,非map类

  FileOutputFormat.setOutputPath(job, segment);

  job.setOutputFormat(FetcherOutputFormat.class);//主要是实现了getRecordWriter这个方法,用于得到相应的数据写出对象

  job.setOutputKeyClass(Text.class);

  job.setOutputValueClass(NutchWritable.class);


  Fetcher类调用多线程进行采集,然后在FetcherOutputFormat类实现数据保存

   FetcherOutputFormat实现了getRecordWriter方法

    Path out = FileOutputFormat.getOutputPath(job);// 定义输出目录

  final Path fetch = new Path(new Path(out, CrawlDatum.FETCH_DIR_NAME), name);// 定义抓取的输出目录

  final Path content = new Path(new Path(out, Content.DIR_NAME), name);// 定义抓取内容的输出目录

  final CompressionType compType = SequenceFileOutputFormat.getOutputCompressionType(job);// 定义数据压缩格式

  final MapFile.Writer fetchOut = new MapFile.Writer(job, fs, fetch.toString(), Text.class, CrawlDatum.class, compType, progress);// 定义抓取的输出抽象类


最后调用write方法去保存相应的文件。

mongoDB在这块进行拦截即可。


2,nutch网页内容的保存到MongoDB

首先在FetcherOutputFormat的getRecordWriter方法初始化mongoDB的工具类

final MongoUtil mongoUtil = new MongoUtil("hadoop37", "nutch");

然后在write方法中进行存储

public void write(Text key, NutchWritable value) throws IOException {

     // 对对象类型进行判断,调用相应的抽象输出,写到不同的文件中去

    Writable w = value.get();

    if (w instanceof CrawlDatum){

// System.out.println("((CrawlDatum) w).getStatus():"+((CrawlDatum) w).getStatus());

// System.out.println("CrawlDatum--"+key.toString()+":");

     fetchOut.append(key, w);

     

     //保存到mongoDB

     Map<String, Object> map = ((CrawlDatum) w).toMap();

     map.put("id", key.toString());

     mongoUtil.insert("crawlDatum", map);

    }

    else if (w instanceof Content){

     contentOut.append(key, w);

     Map<String, Object> map = ((Content) w).toMap();

     map.put("id", key.toString());

     mongoUtil.insert("content", map);

    }

    else if (w instanceof Parse){//默认不开启

    parseOut.write(key, (Parse) w); 

    }

   }


实际上只需要保存CrawlDatum和Content的数据即可。由于mongodDB存储数据以MAP的形式保存,所以需要将CrawlDatum和Content的数据toMap,参考toString

比如CrawlDatum:

/**

  * 返回map集合

  * 2015年1月26日 joker4j自定义

  * @return

  */

 public Map<String,Object> toMap(){

  Map<String, Object> map = new HashMap<String, Object>();

 

  map.put("Version", CUR_VERSION);

  map.put("Status", getStatus());

  map.put("StatusName", getStatusName(getStatus()));

  map.put("Fetch time", new Date(getFetchTime()));

  map.put("Modified time", new Date(getModifiedTime()));

  map.put("Retries since fetch", getRetriesSinceFetch());

  map.put("Retry interval", getFetchInterval());

  map.put("Score", getScore());

  map.put("Signature", StringUtil.toHexString(getSignature()));

 

  if (metaData != null) {

   for (Entry<Writable, Writable> e : metaData.entrySet()) {

    map.put(e.getKey().toString().replace(".", "_"), e.getValue().toString());

   }

  }

 

  return map;

 }


如此即可实现采集完毕一层即可保存在segment目录下的同时,也保存一份数据到mongoDB中。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值