﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-Good Good code,Day Day up-文章分类-Algorithm</title><link>http://www.cppblog.com/dawnbreak/category/8919.html</link><description>PearLi's Blog</description><language>zh-cn</language><lastBuildDate>Thu, 03 Sep 2009 03:12:46 GMT</lastBuildDate><pubDate>Thu, 03 Sep 2009 03:12:46 GMT</pubDate><ttl>60</ttl><item><title>Hadoop学习笔记一 简要介绍 </title><link>http://www.cppblog.com/dawnbreak/articles/95178.html</link><dc:creator>pear_li</dc:creator><author>pear_li</author><pubDate>Thu, 03 Sep 2009 02:58:00 GMT</pubDate><guid>http://www.cppblog.com/dawnbreak/articles/95178.html</guid><wfw:comment>http://www.cppblog.com/dawnbreak/comments/95178.html</wfw:comment><comments>http://www.cppblog.com/dawnbreak/articles/95178.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/dawnbreak/comments/commentRss/95178.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/dawnbreak/services/trackbacks/95178.html</trackback:ping><description><![CDATA[<span style="FONT-SIZE: 14pt">&nbsp;&nbsp;&nbsp; 这里先大致介绍一下Hadoop.<br>&nbsp;&nbsp;&nbsp; 本文大部分内容都是从官网</span><a title=Hadoop href="http://lucene.apache.org/hadoop"><span style="FONT-SIZE: 14pt"><font color=#009933>Hadoop</font></span></a><span style="FONT-SIZE: 14pt">上来的。其中有一篇</span><a title=介绍HDFS的pdf文档 href="http://lucene.apache.org/hadoop/hdfs_design.pdf"><span style="FONT-SIZE: 14pt"><font color=#009933>介绍HDFS的pdf文档</font></span></a><span style="FONT-SIZE: 14pt">，里面对Hadoop介绍的比较全面了。我的这一个系列的Hadoop学习笔记也是从</span><a title=这里 href="http://wiki.apache.org/lucene-hadoop/GettingStartedWithHadoop"><span style="FONT-SIZE: 14pt"><font color=#009933>这里</font></span></a><span style="FONT-SIZE: 14pt">一步一步进行下来的，同时又参考了网上的很多文章，对学习Hadoop中遇到的问题进行了归纳总结。<br>&nbsp;&nbsp;&nbsp; 言归正传，先说一下Hadoop的来龙去脉。谈到Hadoop就不得不提到</span><a title=Lucene href="http://lucene.apache.org/"><span style="FONT-SIZE: 14pt"><font color=#009933>Lucene</font></span></a><span style="FONT-SIZE: 14pt">和</span><a title=Nutch href="http://lucene.apache.org/nutch/"><span style="FONT-SIZE: 14pt"><font color=#009933>Nutch</font></span></a><span style="FONT-SIZE: 14pt">。首先，<span style="COLOR: #0000ff">Lucene并不是一个应用程序，而是提供了一个纯Java的高性能全文索引引擎工具包</span>，它可以方便的嵌入到各种实际应用中实现全文搜索/索引功能。<span style="COLOR: #0000ff">Nutch是一个应用程序，是一个以Lucene为基础实现的搜索引擎应用</span>，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成为了一个分布式的计算平台。<br>&nbsp;&nbsp;&nbsp;其实，Hadoop并不仅仅是一个用于存储的分布式文件系统，而是设计用来在由通用计算设备组成的大型集群上执行分布式应用的框架。<br><br>&nbsp;&nbsp;&nbsp;<span style="COLOR: #0000ff">Hadoop包含两个部分：</span><br><br>&nbsp;&nbsp;&nbsp;<strong>1、HDFS<br></strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;即Hadoop Distributed File System (Hadoop分布式文件系统)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HDFS具有高容错性，并且可以被部署在低价的硬件设备之上。HDFS很适合那些有大数据集的应用，并且提供了对数据读写的高吞吐率。HDFS是一个master/slave的结构，就通常的部署来说，在master上只运行一个Namenode，而在每一个slave上运行一个Datanode。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HDFS支持传统的层次文件组织结构，同现有的一些文件系统在操作上很类似，比如你可以创建和删除一个文件，把一个文件从一个目录移到另一个目录，重命名等等操作。Namenode管理着整个分布式文件系统，对文件系统的操作（如建立、删除文件和文件夹）都是通过Namenode来控制。&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;下面是HDFS的结构：</span><br>
<div align=center src_cetemp="/images/cnblogs_com/wayne1017/HDFSArch.JPG">
<div align=center src_cetemp="/images/cnblogs_com/wayne1017/HDFSArch.JPG"><img height=645 alt="" src="http://images.cnblogs.com/cnblogs_com/wayne1017/HDFSArch.JPG" width=861 border=0></div>
</div>
<br><span style="FONT-SIZE: 14pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从上面的图中可以看出，Namenode，Datanode，Client之间的通信都是建立在TCP/IP的基础之上的。当Client要执行一个写入的操作的时候，命令不是马上就发送到Namenode，Client首先在本机上临时文件夹中缓存这些数据，当临时文件夹中的数据块达到了设定的Block的值（默认是64M）时，Client便会通知Namenode，Namenode便响应Client的RPC请求，将文件名插入文件系统层次中并且在Datanode中找到一块存放该数据的block，同时将该Datanode及对应的数据块信息告诉Client，Client便这些本地临时文件夹中的数据块写入指定的数据节点。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HDFS采取了副本策略，其目的是为了提高系统的可靠性，可用性。HDFS的副本放置策略是三个副本，一个放在本节点上，一个放在同一机架中的另一个节点上，还有一个副本放在另一个不同的机架中的一个节点上。当前版本的hadoop0.12.0中还没有实现，但是正在进行中，相信不久就可以出来了。<br><br>&nbsp;&nbsp;&nbsp;<strong>2、MapReduce的实现<br></strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><a title=MapReduce href="http://labs.google.com/papers/mapreduce.html"><span style="FONT-SIZE: 14pt"><font color=#009933>MapReduce</font></span></a><span style="FONT-SIZE: 14pt">是Google 的一项重要技术，它是一个编程模型，用以进行大数据量的计算。对于大数据量的计算，通常采用的处理手法就是并行计算。至少现阶段而言，对许多开发人员来说，并行计算还是一个比较遥远的东西。MapReduce就是一种简化并行计算的编程模型，它让那些没有多少并行计算经验的开发人员也可以开发并行应用。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MapReduce的名字源于这个模型中的两项核心操作：Map和 Reduce。也许熟悉Functional Programming（</span><a title=函数式编程 href="http://chn.blogbeta.com/232.html"><span style="FONT-SIZE: 14pt"><font color=#009933>函数式编程</font></span></a><span style="FONT-SIZE: 14pt">）的人见到这两个词会倍感亲切。简单的说来，Map是把一组数据一对一的映射为另外的一组数据，其映射的规则由一个函数来指定，比如对[1, 2, 3, 4]进行乘2的映射就变成了[2, 4, 6, 8]。Reduce是对一组数据进行归约，这个归约的规则由一个函数指定，比如对[1, 2, 3, 4]进行求和的归约得到结果是10，而对它进行求积的归约结果是24。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;关于MapReduce的内容，建议看看孟岩的这篇</span><a title="MapReduce:The free lunch is not over!" href="http://www.mengyan.org/blog/archives/2006/11/15/138.html"><span style="FONT-SIZE: 14pt"><font color=#009933>MapReduce:The Free Lunch Is Not Over!</font></span></a><br><br><span style="FONT-SIZE: 14pt">&nbsp;&nbsp;&nbsp;好了，作为这个系列的第一篇就写这么多了，我也是刚开始接触Hadoop，下一篇就是讲Hadoop的部署，谈谈我在部署Hadoop时遇到的问题，也给大家一个参考，少走点弯路。</span>
<div class=diggit onclick=DiggIt(668768,20676,1)>&nbsp;</div>
<img src ="http://www.cppblog.com/dawnbreak/aggbug/95178.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/dawnbreak/" target="_blank">pear_li</a> 2009-09-03 10:58 <a href="http://www.cppblog.com/dawnbreak/articles/95178.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Map Reduce - the Free Lunch is not over?</title><link>http://www.cppblog.com/dawnbreak/articles/95176.html</link><dc:creator>pear_li</dc:creator><author>pear_li</author><pubDate>Thu, 03 Sep 2009 02:43:00 GMT</pubDate><guid>http://www.cppblog.com/dawnbreak/articles/95176.html</guid><wfw:comment>http://www.cppblog.com/dawnbreak/comments/95176.html</wfw:comment><comments>http://www.cppblog.com/dawnbreak/articles/95176.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/dawnbreak/comments/commentRss/95176.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/dawnbreak/services/trackbacks/95176.html</trackback:ping><description><![CDATA[<div id=main>
<div id=contentwrapper>
<div class=topPost>
<h2 class=topTitle><a href="http://www.mengyan.org/blog/archives/2006/11/15/138.html"><font color=#ffffff size=5>Map Reduce - the Free Lunch is not over?</font></a></h2>
<p class=topMeta>by <a title="Posts by Meng Yan" href="http://www.mengyan.org/blog/archives/author/meng-yan/"><u><font color=#ffffff>Meng Yan</font></u></a> on Nov.15, 2006, under <a title="View all posts in Other" href="http://www.mengyan.org/blog/archives/category/other" rel="category tag"><u><font color=#ffffff>Other</font></u></a></p>
<div class=topContent>
<p>微软著名的C++大师<a href="http://www.gotw.ca/"><u><font color=#ffffff>Herb Sutter</font></u></a>在2005年初的时候曾经写过一篇重量级的文章：&#8221;<a href="http://www.gotw.ca/publications/concurrency-ddj.htm"><u><font color=#ffffff>The Free Lunch Is Over: A Fundamental Turn Toward Concurrency in Software</font></u></a>&#8220;，预言OO之后软件开发将要面临的又一次重大变革-并行计算。</p>
<p>摩尔定律统制下的软件开发时代有一个非常有意思的现象：&#8221;Andy giveth, and Bill taketh away.&#8221;。不管CPU的主频有多快，我们始终有办法来利用它，而我们也陶醉在机器升级带来的程序性能提高中。</p>
<p>我记着我大二的时候曾经做过一个五子棋的程序，当时的算法就是预先设计一些棋型（有优先级），然后扫描棋盘，对形势进行分析，看看当前走哪部对自己最重要。当然下棋还要堵别人，这就需要互换双方的棋型再计算。如果只算一步，很可能被狡猾的对手欺骗，所以为了多想几步，还需要递归和回朔。在当时的机器上，算3步就基本上需要3秒左右的时间了。后来大学毕业收拾东西的时候找到这个程序，试了一下，发现算10步需要的时间也基本上感觉不出来了。</p>
<p>不知道你是否有同样的经历，我们不知不觉的一直在享受着这样的免费午餐。可是，随着摩尔定律的提前终结，免费的午餐终究要还回去。虽然硬件设计师还在努力：Hyper Threading CPU（多出一套寄存器，相当于一个逻辑CPU）使得Pipeline尽可能满负荷，使多个Thread的操作有可能并行，使得多线程程序的性能有5%-15%的提升；增加Cache容量也使得包括Single-Thread和Multi-Thread程序都能受益。也许这些还能帮助你一段时间，但问题是，我们必须做出改变，面对这个即将到来的变革，你准备好了么？</p>
<p>Concurrency Programming != Multi-Thread Programming。很多人都会说MultiThreading谁不会，问题是，你是为什么使用/如何使用多线程的？我从前做过一个类似AcdSee一样的图像查看/处理程序，我通常用它来处理我的数码照片。我在里面用了大量的多线程，不过主要目的是在图像处理的时候不要Block住UI，所以将CPU Intensive的计算部分用后台线程进行处理。而并没有把对图像矩阵的运算并行分开。</p>
<p>我觉得Concurrency Programming真正的挑战在于Programming Model的改变，在程序员的脑子里面要对自己的程序怎样并行化有很清楚的<strong>认识</strong>，更重要的是，如何去<strong>实现</strong>（包括架构、容错、实时监控等等）这种并行化，如何去<strong>调试</strong>，如何去<strong>测试</strong>。</p>
<p>在Google，每天有海量的数据需要在有限的时间内进行处理（其实每个互联网公司都会碰到这样的问题），每个程序员都需要进行分布式的程序开发，这其中包括如何分布、调度、监控以及容错等等。Google的<a href="http://labs.google.com/papers/mapreduce.html"><u><font color=#ffffff>MapReduce</font></u></a>正是把分布式的业务逻辑从这些复杂的细节中抽象出来，使得没有或者很少并行开发经验的程序员也能进行并行应用程序的开发。</p>
<p>MapReduce中最重要的两个词就是Map（映射）和Reduce（规约）。初看Map/Reduce这两个词，熟悉Function Language的人一定感觉很熟悉。FP把这样的函数称为&#8221;higher order function&#8221;（&#8221;High order function&#8221;被成为Function Programming的利器之一哦），也就是说，这些函数是编写来被与其它函数相结合（或者说被其它函数调用的）。如果说硬要比的化，可以把它想象成C里面的CallBack函数，或者STL里面的Functor。比如你要对一个STL的容器进行查找，需要制定每两个元素相比较的Functor（Comparator），这个Comparator在遍历容器的时候就会被调用。</p>
<p>拿前面说过图像处理程序来举例，其实大多数的图像处理操作都是对图像矩阵进行某种运算。这里的运算通常有两种，一种是映射，一种是规约。拿两种效果来说，&#8221;老照片&#8221;效果通常是强化照片的G/B值，然后对每个象素加一些随机的偏移，这些操作在二维矩阵上的每一个元素都是独立的，是Map操作。而&#8221;雕刻&#8221;效果需要提取图像边缘，就需要元素之间的运算了，是一种Reduce操作。再举个简单的例子，一个一维矩阵（数组）[0,1,2,3,4]可以映射为[0,2,3,6,8]（乘2），也可以映射为[1,2,3,4,5]（加1）。它可以规约为0（元素求积）也可以规约为10（元素求和）。</p>
<p>面对复杂问题，古人教导我们要&#8220;<strong>分</strong>而<strong>治</strong>之&#8221;，英文中对应的词是&#8221;<strong>Divide</strong> and <strong>Conquer</strong>&#8220;。Map/Reduce其实就是Divide/Conquer的过程，通过把问题Divide，使这些Divide后的Map运算高度并行，再将Map后的结果Reduce（根据某一个Key），得到最终的结果。</p>
<p>Googler发现这是问题的核心，其它都是共性问题。因此，他们把MapReduce抽象分离出来。这样，Google的程序员可以只关心应用逻辑，关心根据哪些Key把问题进行分解，哪些操作是Map操作，哪些操作是Reduce操作。其它并行计算中的复杂问题诸如分布、工作调度、容错、机器间通信都交给Map/Reduce Framework去做，很大程度上简化了整个编程模型。</p>
<p>MapReduce的另一个特点是，Map和Reduce的<strong>输入和输出都是中间临时文件</strong>（MapReduce利用Google文件系统来管理和访问这些文件），而不是不同进程间或者不同机器间的其它通信方式。我觉得，这是Google一贯的风格，化繁为简，返璞归真。</p>
<p>接下来就放下其它，研究一下Map/Reduce操作。（其它比如容错、备份任务也有很经典的经验和实现，论文里面都有详述）</p>
<p>Map的定义：</p>
<blockquote>
<p>Map, written by the user, takes an input pair and produces a set of intermediate key/value pairs. The MapReduce library groups together all intermediate values associated with the same intermediate key I and passes them to the Reduce function.</p>
</blockquote>
<p>Reduce的定义：</p>
<blockquote>
<p>The Reduce function, also written by the user, accepts an intermediate key I and a set of values for that key. It merges together these values to form a possibly smaller set of values. Typically just zero or one output value is produced per Reduce invocation. The intermediate values are supplied to the user&#8217;s reduce function via an iterator. This allows us to handle lists of values that are too large to fit in memory.</p>
</blockquote>
<p>MapReduce论文中给出了这样一个例子：在一个文档集合中统计每个单词出现的次数。</p>
<p>Map操作的输入是每一篇文档，将输入文档中每一个单词的出现输出到中间文件中去。</p>
<blockquote>
<p>map(String key, String value):<br>&nbsp;&nbsp;&nbsp; // key: document name<br>&nbsp;&nbsp;&nbsp; // value: document contents<br>&nbsp;&nbsp;&nbsp; for each word w in value:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EmitIntermediate(w, &#8220;1&#8243;);</p>
</blockquote>
<p>比如我们有两篇文档，内容分别是</p>
<p>A － &#8220;I love programming&#8221;</p>
<p>B － &#8220;I am a blogger, you are also a blogger&#8221;。</p>
<p>B文档经过Map运算后输出的中间文件将会是：</p>
<pre>	I,1
am,1
a,1
blogger,1
you,1
are,1
a,1
blogger,1
</pre>
<p>Reduce操作的输入是单词和出现次数的序列。用上面的例子来说，就是 (&#8221;I&#8221;, [1, 1]), (&#8221;love&#8221;, [1]), (&#8221;programming&#8221;, [1]), (&#8221;am&#8221;, [1]), (&#8221;a&#8221;, [1,1]) 等。然后根据每个单词，算出总的出现次数。</p>
<blockquote>
<p>reduce(String key, Iterator values):<br>&nbsp;&nbsp;&nbsp; // key: a word<br>&nbsp;&nbsp;&nbsp; // values: a list of counts<br>&nbsp;&nbsp;&nbsp; int result = 0;<br>&nbsp;&nbsp;&nbsp; for each v in values:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; result += ParseInt(v);<br>&nbsp;&nbsp;&nbsp; Emit(AsString(result));</p>
</blockquote>
<p>最后输出的最终结果就会是：(&#8221;I&#8221;, 2&#8243;), (&#8221;a&#8221;, 2&#8243;)&#8230;&#8230;</p>
<p>实际的执行顺序是：</p>
<ol>
    <li>MapReduce Library将Input分成M份。这里的Input Splitter也可以是多台机器<strong><font size=2>并行Split</font></strong>。
    <li>Master将M份Job分给Idle状态的M个worker来处理；
    <li>对于输入中的每一个&lt;key, value&gt; pair 进行Map操作，将中间结果Buffer在Memory里；
    <li>定期的（或者根据内存状态），将Buffer中的中间信息Dump到<strong><font size=2>本地</font></strong>磁盘上，并且把文件信息传回给Master（Master需要把这些信息发送给Reduce worker）。这里最重要的一点是，<strong><font size=2>在写磁盘的时候，需要将中间文件做Partition（比如R个）</font></strong>。拿上面的例子来举例，如果把所有的信息存到一个文件，Reduce worker又会变成瓶颈。我们只需要保证<strong><font size=2>相同Key能出现在同一个Partition</font></strong>里面就可以把这个问题分解。
    <li>R个Reduce worker开始工作，从不同的Map worker的Partition那里拿到数据（<strong><font size=2>read the buffered data from the local disks of the map workers</font></strong>），用key进行排序（如果内存中放不下需要用到外部排序 - external sort）。很显然，排序（或者说Group）是Reduce函数之前必须做的一步。 这里面很关键的是，每个Reduce worker会去从很多Map worker那里拿到X(0&lt;X&lt;R) Partition的中间结果，这样，所有属于这个Key的信息已经都在这个worker上了。
    <li>Reduce worker遍历中间数据，对每一个唯一Key，执行Reduce函数（参数是这个key以及相对应的一系列Value）。
    <li>执行完毕后，唤醒用户程序，返回结果（最后应该有R份Output，每个Reduce Worker一个）。 </li>
</ol>
<p>可见，这里的分（Divide）体现在两步，分别是将输入分成M份，以及将Map的中间结果分成R份。将输入分开通常很简单，Map的中间结果通常用&#8221;hash(key) mod R&#8221;这个结果作为标准，保证相同的Key出现在同一个Partition里面。当然，使用者也可以指定自己的Partition Function，比如，对于Url Key，如果希望同一个Host的URL出现在同一个Partition，可以用&#8221;hash(Hostname(urlkey)) mod R&#8221;作为Partition Function。</p>
<p>对于上面的例子来说，每个文档中都可能会出现成千上万的 (&#8221;the&#8221;, 1)这样的中间结果，琐碎的中间文件必然导致传输上的损失。因此，MapReduce还支持用户提供Combiner Function。这个函数通常与Reduce Function有相同的实现，不同点在于Reduce函数的输出是最终结果，而Combiner函数的输出是Reduce函数的某一个输入的中间文件。</p>
<p>Tom White给出了Nutch[2]中另一个很直观的例子，<a href="http://weblogs.java.net/blog/tomwhite/archive/2005/09/mapreduce.html"><u><font color=#ffffff>分布式Grep</font></u></a>。我一直觉得，Pipe中的很多操作，比如More、Grep、Cat都类似于一种Map操作，而Sort、Uniq、wc等都相当于某种Reduce操作。</p>
<p>加上前两天Google刚刚发布的<a href="http://labs.google.com/papers/bigtable.html"><u><font color=#ffffff>BigTable</font></u></a>论文，现在Google有了自己的集群 - <a href="http://labs.google.com/papers/googlecluster.html"><u><font color=#ffffff>Googel Cluster</font></u></a>，分布式文件系统 - <a href="http://labs.google.com/papers/gfs.html"><u><font color=#ffffff>GFS</font></u></a>，分布式计算环境 - <a href="http://labs.google.com/papers/mapreduce.html"><u><font color=#ffffff>MapReduce</font></u></a>，分布式结构化存储 - <a href="http://labs.google.com/papers/bigtable.html"><u><font color=#ffffff>BigTable</font></u></a>，再加上<a href="http://labs.google.com/papers/chubby.html"><u><font color=#ffffff>Lock Service</font></u></a>。我真的能感觉的到Google著名的免费晚餐之外的对于程序员的另一种免费的晚餐，那个由大量的commodity PC组成的large clusters。我觉得这些才真正是Google的核心价值所在。</p>
<p>呵呵，就像微软老兵<a href="http://www.joelonsoftware.com/"><u><font color=#ffffff>Joel Spolsky</font></u></a>（你应该看过他的&#8221;Joel on Software&#8221;吧？）曾经说过，对于微软来说最可怕的是[1]，微软还在苦苦追赶Google来完善Search功能的时候，Google已经在部署下一代的超级计算机了。</p>
<blockquote>
<p>The very fact that Google invented MapReduce, and Microsoft didn&#8217;t, says something about why <strong>Microsoft is still playing catch up trying to get basic search features to work, while Google has moved on to the next problem: building Skynet^H^H^H^H^H^H the world&#8217;s largest massively parallel supercomputer</strong>. I don&#8217;t think Microsoft completely understands just how far behind they are on that wave.</p>
</blockquote>
<p>注1：其实，微软也有自己的方案 - <a href="http://research.microsoft.com/research/sv/dryad/"><u><font color=#ffffff>DryAd</font></u></a>。问题是，大公司里，要想重新部署这样一个底层的InfraStructure，无论是技术的原因，还是政治的原因，将是如何的难。</p>
<p>注2：<a href="http://lucene.apache.org/"><u><font color=#ffffff>Lucene</font></u></a>之父Doug Cutting的又一力作，Project <a href="http://lucene.apache.org/hadoop/"><u><font color=#ffffff>Hadoop</font></u></a>&nbsp;- 由Hadoop分布式文件系统和一个Map/Reduce的实现组成，Lucene/Nutch的成产线也够齐全的了。</p>
</div>
</div>
</div>
</div>
<img src ="http://www.cppblog.com/dawnbreak/aggbug/95176.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/dawnbreak/" target="_blank">pear_li</a> 2009-09-03 10:43 <a href="http://www.cppblog.com/dawnbreak/articles/95176.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>