Nutch中MapReduce的分析

Google MapReduce研究综述

MapReduce研究探讨体会
MapReduce : Simplified Data Processing on Large Clusters

 

MapReduce基础   未读

Hadoop 分布式计算技术专题

 

 

 

Nutch 是最早用MapReduce的项目 (Hadoop其实原来是Nutch的一部分),Nutch的plugin机制吸取了eclipse的plugin设计思路。

在Nutch中 MapReduce编程方式占据了其核心的结构大部分。从插入url列表(Inject),生成抓取列表(Generate),抓取内容(Fetch), 分析处理内容(Parse),更新Crawl DB库(Update ),转化链接(Invert Links)一直到建立索引(Index)都是采用MapReduce来完成的。查看Nutch的源代码我们能够学到更多的 如何用MapReduce来处理我们编程中所遇到的问题。

Nutch从获取下载列表到建立索引的过程:

插入url列表到Crawl DB,引导下面的抓取程序
循环:
– 从Crawl DB生成一些url列表;
– 抓取内容;
– 分析处理抓取的内容;
– 更新Crawl DB库.
转化每个页面中外部对它的链接
建立索引

 

具体技术实现细节:

1。插入url列表(Inject)

MapReduce程序1:
目标:转换input输入为CrawlDatum格式.
输入: url文件
Map(line) → <url, CrawlDatum>
Reduce()合并多重的Url.
输出:临时的CrawlDatum文件.
MapReduce2:
目标:合并上一步产生的临时文件到新的DB
输入: 上次MapReduce输出的CrawlDatum
Map()过滤重复的url.
Reduce: 合并两个CrawlDatum到一个新的DB
输出:CrawlDatum

2。生成抓取列表(Generate)

MapReduce程序1:
目标:选择抓取列表
输入: Crawl DB 文件
Map() → 如果抓取当前时间大于现在时间 ,抓换成 <CrawlDatum, url>格式.
分发器(Partition) :用url的host保证同一个站点分发到同一个Reduce程序上.
Reduce:取最顶部的N个链接.
MapReduce程序2:
目标:准备抓取
Map() 抓换成 <url,CrawlDatum,>格式
分发器(Partition) :用url的host
输出:<url,CrawlDatum>文件

3。抓取内容(Fetch)

MapReduce:
目标:抓取内容
输入: <url,CrawlDatum>, 按host划分, 按hash排序
Map(url,CrawlDatum) → 输出<url, FetcherOutput>
多线程, 调用Nutch的抓取协议插件,抓取输出<CrawlDatum, Content>
输出: <url,CrawlDatum>, <url,Content>两个文件

4。分析处理内容(Parse)

MapReduce:
目标:处理抓取的能容
输入: 抓取的<url, Content>
Map(url, Content) → <url, Parse>
调用Nutch的解析插件,输出处理完的格式是<ParseText, ParseData>
输出: <url,ParseText>, <url,ParseData><url,CrawlDatum>.

5。更新Crawl DB库(Update )

MapReduce:
目标: 整合 fetch和parse到DB中
输入:<url,CrawlDatum> 现有的db加上fetch和parse的输出,合并上面3个DB为一个新的DB
输出: 新的抓取DB

6。转化链接(Invert Links)

MapReduce:
目标:统计外部页面对本页面链接
输入: <url,ParseData>, 包含页面往外的链接
Map(srcUrl, ParseData> → <destUrl, Inlinks>
搜集外部对本页面的链接Inlinks格式:<srcUrl, anchorText>
Reduce() 添加inlinks
输出: <url, Inlinks>

7。建立索引(Index)

MapReduce:
目标:生成Lucene索引
输入: 多种文件格式
parse处理完的<url, ParseData> 提取title, metadata信息等
parse处理完的<url, ParseText> 提取text内容
转换链接处理完的<url, Inlinks> 提取anchors
抓取内容处理完的<url, CrawlDatum> 提取抓取时间.
Map() 用ObjectWritable包裹上面的内容
Reduce() 调用Nutch的索引插件,生成Lucene Document文档
输出: 输出Lucene索引

 

本文来自 http://www.hadoop.org.cn/mapreduce/nutch-mapreduce/

***************************************************************************************

Crawl the Nutch -- Map Reduce

初见于Google Lab的Paper, http://labs.google.com/papers/mapreduce.html ,论文中表明在有大量集群支撑的情况下,可以快速的在海量文档中进行数据处理。现在你有一堆数据,你需要按记录修改、查询、插入和删除,一种办法是你为这些记录建立索引,比如放入数据库,还有一种办法就是--MapReduce。这种处理方式实际上是在数据存放的时候不建立索引,等实际处理数据的时候再将这些数据读入内存进行排序,并可以用Partitioner将数据分在不同的机器上同时进行处理,因此可以方便的实现集群计算,我猜想在一台机器上存放的数据容量以能够全部装进内存为限。

   MapReduce把对数据记录的所有操作都归结两个步骤--Map和Reduce。其中Map对现有数据做一个先期处理,
得到一个中间数据集,Reduce再对中间数据集进行去重、过滤等后期处理,最后得到你要的结果。Hadoop是一个MapReduce的实现,Nutch项目的大容量数据处理等功能就构建在Hadoop之上。

过程原形:
Map :: (InitialKey, IntialValue) -> [(InterKey, InterValue)]
Reduce :: (Interkey, InterValuesIterator) -> [(InterKey, InterValue)]
Map接收一个Key、Value对,返回一个Key、Value对(如果原始的Key、Value对不满足你的要求你可以不返回,或者你有特殊需求也可以返回多个,一般比较少见), Reduce接收一个Key和一个Values的Iterator,你可以根据情况返回零个或多个Key,Value对。Key是一个实现了org.apache.hadoop.WritableComparable接口的类,Value则实现了Writable,WritableComparable是Writable的子接口,Writable定义了输入输出(序列化)的接口,WritableComparable另外继承Comparable,因此Key总是有序的。

一个使用MapReduce的功能块典型结构如下:
新建一个JobConf
设置输入路径
设置输入文件格式
设置输入Key,Value类型
设置输出路径
设置输出文件格式
设置输出Key,Value类型
设置Partitioner
启动Job

执行完毕,你所有存放在输入路径下的数据都在被转换之后按照你指定的格式存放于输出路径中,


ok,我知道很多人都是看code比看document更兴奋,很不幸,我也是其中一员。

. 排序
比如你有一批URL,存放在文本文件c:/tmp/tmpin/urllist.txt中,一行一个
http://www.sohu.com
http://www.163.com
http://www.sina.com.cn
...

输入格式一般是SequenceFileInputFormat,但是对于urllist.txt这种按行排列的格式却是另外一种(我不知道的)格式,简单来说就是你不需要设定输入格式就能处理它了,在MapReduce传递给你的Map时,你可以忽略Key值,
而Value就是URL了,然后你做一个转换把Value(URL)作为Key来存放,然后你自己合成一个Value值,比如只是简单的一个数字1,或者是一个URL的相关信息,DocumentId, 预计抓取时间等。因为这次的任务是排序,而事实上经过Map处理后数据已经是按Key(URL)排好序了,所以Reduce可以什么也不做。
public class Main {
 public static class InjectMapper extends MapReduceBase implements Mapper {
  public void map(WritableComparable key, Writable val,
    OutputCollector output, Reporter reporter) throws IOException {
   UTF8 url = (UTF8) val;
   UTF8 v = new UTF8("1");
   output.collect(url, v); //生成数据
  }
 }
        
        public static void main(String[] args) throws IOException {
  JobConf job = new JobConf();
  Path urlsPath = new Path("C:/tmp/tmpin");
  job.setInputPath(urlsPath);
  Path outputPath = new Path("c:/tmp/tmpout");
  job.setOutputPath(outputPath);
  job.setOutputFormat(SequenceFileOutputFormat.class);
  job.setOutputKeyClass(UTF8.class);
  job.setOutputValueClass(UTF8.class);

  job.setMapperClass(InjectMapper.class);
  //job.setReduceClass(InjectReducer.class);
  JobClient.runJob(job);
 }
}

. 去重
你的原始URL列表中可能有相同的URL,去除相同Key值记录的功能就需要Reduce了,定义一个类
 public static class InjectReducer extends MapReduceBase implements Reducer {
  public void reduce(WritableComparable key, Iterator values,
    OutputCollector output, Reporter reporter) throws IOException {
   output.collect(key, (Writable) values.next());
  }
 }
并传递给JobConf就Ok了,由此可以看出Reduce过程对于同一个Key只被调用一次,那个values的Iterator包含这个Key所对应的全部记录,你可以简单的只取第一条数据,对这些记录进行比较,得到你认为最有效的一条记录,或者统计每一个Key都有多少条记录,一句话,你可以做任何事情(事实上是任何MapReduce所支持的事情)。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/wilbur727/archive/2007/09/26/1801699.aspx

 

Hadoop学习笔记一 简要介绍

本文大部分内容都是从官网Hadoop上来的。其中有一篇介绍HDFS的pdf文档,里面对Hadoop介绍的比较全面了。我的这一个系列的Hadoop学习笔记也是从这里一步一步进行下来的,同时又参考了网上的很多文章,对学习Hadoop中遇到的问题进行了归纳总结。

  言归正传,先说一下Hadoop的来龙去脉。谈到Hadoop就不得不提到Lucene和Nutch。首先,Lucene并不是一个应用程序,而是提供了一个纯Java的高性能全文索引引擎工具包,它可以方便的嵌入到各种实际应用中实现全文搜索/索引功能。Nutch是一个应用程序,是一个以Lucene为基础实现的搜索引擎应用,Lucene为Nutch提供了文本搜索和索引的API,Nutch不光有搜索的功能,还有数据抓取的功能。在nutch0.8.0版本之前,Hadoop还属于Nutch的一部分,而从nutch0.8.0开始,将其中实现的NDFS和MapReduce剥离出来成立一个新的开源项目,这就是Hadoop,而nutch0.8.0版本较之以前的Nutch在架构上有了根本性的变化,那就是完全构建在Hadoop的基础之上了。在Hadoop中实现了Google的GFS和MapReduce算法,使Hadoop成为了一个分布式的计算平台。

  其实,Hadoop并不仅仅是一个用于存储的分布式文件系统,而是设计用来在由通用计算设备组成的大型集群上执行分布式应用的框架。

  Hadoop包含两个部分:

  1、HDFS

  即Hadoop Distributed File System (Hadoop分布式文件系统)

  HDFS具有高容错性,并且可以被部署在低价的硬件设备之上。HDFS很适合那些有大数据集的应用,并且提供了对数据读写的高吞吐率。HDFS是一个master/slave的结构,就通常的部署来说,在master上只运行一个Namenode,而在每一个slave上运行一个Datanode。

  HDFS支持传统的层次文件组织结构,同现有的一些文件系统在操作上很类似,比如你可以创建和删除一个文件,把一个文件从一个目录移到另一个目录,重命名等等操作。Namenode管理着整个分布式文件系统,对文件系统的操作(如建立、删除文件和文件夹)都是通过Namenode来控制。

  下面是HDFS的结构:

  从上面的图中可以看出,Namenode,Datanode,Client之间的通信都是建立在TCP/IP的基础之上的。当Client要执行一个写入的操作的时候,命令不是马上就发送到Namenode,Client首先在本机上临时文件夹中缓存这些数据,当临时文件夹中的数据块达到了设定的Block的值(默认是64M)时,Client便会通知Namenode,Namenode便响应Client的RPC请求,将文件名插入文件系统层次中并且在Datanode中找到一块存放该数据的block,同时将该Datanode及对应的数据块信息告诉Client,Client便这些本地临时文件夹中的数据块写入指定的数据节点。

  HDFS采取了副本策略,其目的是为了提高系统的可靠性,可用性。HDFS的副本放置策略是三个副本,一个放在本节点上,一个放在同一机架中的另一个节点上,还有一个副本放在另一个不同的机架中的一个节点上。当前版本的hadoop0.12.0中还没有实现,但是正在进行中,相信不久就可以出来了。

  2、MapReduce的实现

  MapReduce是Google 的一项重要技术,它是一个编程模型,用以进行大数据量的计算。对于大数据量的计算,通常采用的处理手法就是并行计算。至少现阶段而言,对许多开发人员来说,并行计算还是一个比较遥远的东西。MapReduce就是一种简化并行计算的编程模型,它让那些没有多少并行计算经验的开发人员也可以开发并行应用。

  MapReduce的名字源于这个模型中的两项核心操作:Map和 Reduce。也许熟悉Functional Programming(函数式编程)的人见到这两个词会倍感亲切。简单的说来,Map是把一组数据一对一的映射为另外的一组数据,其映射的规则由一个函数来指定,比如对[1, 2, 3, 4]进行乘2的映射就变成了[2, 4, 6, 8]。Reduce是对一组数据进行归约,这个归约的规则由一个函数指定,比如对[1, 2, 3, 4]进行求和的归约得到结果是10,而对它进行求积的归约结果是24。

  关于MapReduce的内容,建议看看孟岩的这篇MapReduce:The Free Lunch Is Not Over!

  好了,作为这个系列的第一篇就写这么多了,我也是刚开始接触Hadoop,下一篇就是讲Hadoop的部署,谈谈我在部署Hadoop时遇到的问题,也给大家一个参考,少走点弯路。

来源:http://www.cnblogs.com/wayne1017/archive/2007/03/18/668768.html

 

**********************************************************************************

 

MapReduce: 一个巨大的倒退

你可能感兴趣的:(mapreduce,hadoop,Google,Lucene,url,iterator)