Answers:
基本上,这是个大问题,但并不难。出差推销员主要取决于任何给定城市对之间的距离,因此,尽管可以将其分解成许多部分,但部分结果无法重新组合,从而出现了全球最优解决方案(嗯,可能不会;如果您知道一种方法,请立即申请您的菲尔兹奖章。
另一方面,对庞大的语料库中的单词频率进行计数是微不足道的,并且是微不足道的重组(您只需将针对语料库各部分计算的向量相加即可),因此map-reduce是显而易见的解决方案。
在实践中,更多的问题往往很容易重组,因此是否并行化任务的决定与任务的规模有多大关系,而与任务的难度有多大关系。
使用分布式计算能否有效解决问题?
如果对这个问题的回答是“是”,则您有MapReduce的候选问题。这是因为问题模式使自己可以分解为较小的孤立问题。
您的任务:解析这本书
一个例子很好地说明了这一点。您有一个大文件(Herman Melville的Moby Dick),您的工作是对其中使用的所有单词进行频率分析。
顺序法
您可以依次购买最快的机器(周围有很多东西)并从头到尾遍历文本,以维护找到的每个单词(键)的哈希图,并每次增加频率(值),从而依次执行此操作你解析一个词。简单,直接和缓慢。
MapReduce方法
从不同的角度处理此问题,您会注意到所有这些备用计算机都在附近,您可以将该任务分解为多个块。给每台机器一个1Mb的文本块,以解析为哈希图,然后将每个哈希图的所有哈希图整理为单个结果。这是一个分层的MapReduce解决方案。
读取一行文本并收集单词的过程是Map阶段(您创建一个简单的map来表示行中单词的频率为1,2,3等),然后Reduce阶段是每台计算机整理其行时映射到单个聚合地图。
总体解决方案来自进一步的Reduce阶段,在该阶段中,所有聚合映射都被聚合(再次输入该单词)为最终映射。稍微复杂一点,大规模并行和快速。
摘要
因此,总而言之,如果您的问题很容易由键,值表示,并且对这些值进行孤立的聚合操作,那么您就有MapReduce的候选问题。
MapReduce模式来自函数式编程领域。这是一个在数据结构上并行应用称为“变形”的过程。函数式程序员几乎每个简单的转换或摘要都使用了变形。
假设您的数据是一棵树,那么决定因素是您是否可以仅使用节点中包含的数据及其子节点的计算值来为其计算值。
例如,您可以使用变形来计算树的大小。您将计算所有子项的计算值之和加一。
这WPI -地图的应用减少(PPT)可能是你的兴趣。它讨论了MR的不同应用,并且作为讨论的案例之一,它展示了纽约时报如何使用100个EC2实例和24小时将4TB扫描的文章转换为1.5TB的PDF文档。
MR帮助提高性能的另一组示例是:Aster-SQL Map Reduce显示了SQL-Map Reduce技术的一些案例研究,包括欺诈检测,转换等。
映射/归约是一种特定算法的特定形式。您可以使用它将一个巨大的数据集转换为另一个数据集。(结果数据集可能很大,也可能不会很大。)如果您不希望由于输入静态数据而设置了静态数据输出,则不建议使用Map / Reduce。Map / Reduce可以轻松告诉您曼哈顿电话簿中有多少John Smiths,但它并不适合构建Web服务器。
Map / Reduce的工作方式是:
结果是将(k1,v1)对的列表转换为(v3)对的列表。(当然,值“ v3”可以是包含k2的组合,可以将其定义为等于k1。)
所以你用它:
如果您有太多的数据需要从一两个服务器顺序运行,那么这将花费很长时间,并且
您可以将输出数据视为值或键值对的列表(当您记得“键”仅表示“唯一标签”时,通常不太难),并且
无论是哪种关系,都可以确保每条输入数据仅影响一个输出键的输出值。
如果您的数据可以由单个服务器按顺序处理,则由于这是主要的计算范例(为服务器构建的服务器和经过培训的程序员),请使用单个服务器。
映射阶段必须通过输出键对所有输入数据进行分区。它不必产生与输出键关联的输出值(由reduce阶段完成),但是它必须唯一地分配每个输入键值对以贡献最多一个输出键的值。如果数据相互关联,则map reduce可能无法解决问题。另一方面,可能只是您需要使用多轮的map / reduce。
如果您不知道如何将数据转换转换为映射/归约,那么这当然不是解决方案。
弄清一个问题是否可以分解为Map / Reduce可以处理的事情是一种真正的艺术。例如,v1和v2可能根本不在输入或输出数据集中。如果只想对输入数据中的唯一项目进行计数,则k1 = k2 =一个项目,而v1 = v2 = 1或0或什至是任何东西。减少只是产生v3作为它给定的k2数量的总和。
因此很难确定使用Map / Reduce无法完成数据转换,但是以上内容为您提供了一些指导。
这里的大多数答案似乎是在解释map reduce所做的事情上的一些变体,这是正确的。但是要回答这个问题,那不是真正解决了哪个模式将发出信号,表明您可能在哪里可以使用map reduce。
如果您要解决的问题的天真的,非功能性的实现包括循环循环某些事物,然后用循环内部的某种状态更新循环外部的某些事物,那么您很有可能会减少一些映射。特别是如果您可以将中心状态的更新概括为只使用两个参数的函数,并且可以保证该函数是可交换的和关联的。
如果确实如此,可能要使用map reduce的原因有两个:1)如果将事物分解为map并缩减函数,它可能会更干净一些,并且更易于测试和调试。2)map reduce函数是无状态的,可以同时运行,如果有多个cpus可用,例如hadoop或spark这样可以在集群中运行事物,则可以加快运行速度。
如果您要遍历许多东西,这很好,但是里程数可能会根据地图/简化的复杂程度而有所不同。最终会出现一个顺序的链或地图缩减树,这很普遍,最终,在链的末尾,所有复杂的归约步骤仍然使所有内容成为瓶颈。例如,许多图形算法仅凭地图缩小就很难有效地缩放。
最适合与map reduce一起使用的最简单的示例是对事物进行计数,这是一种非常便宜的减少。这就是为什么字数统计是map reduce经常使用的示例的原因。您几乎可以期望该用例具有线性可扩展性以提高性能:您添加的每个CPU都使其速度更快。
如果您进行了大量的函数编程,则会开始遇到需要绘制一般贴图并进行简化的情况。您甚至可能在命令式编程中看到了它们,但没有意识到它们是在循环和累加器的掩盖下。
作为最近出现在我眼前的一个例子,我一直在Haskell中研究解析器。为了测试我的解析器,我通过解析器抽取了一系列字符串片段,然后我想获得一个字符串,我可以输出结果以查看其解析是否正确。所以看起来像:
--my initial set of test data, a list
tests = ["string1", "string2", "string3", ...]
--Map Step: turn strings into parsed results
--note the type, which demonstrates the map
applyParser :: [String] -> [Token]
--The actual function
applyParser input = map parser input
--Second map, turn tokens into output
showTokens :: [Token] -> [String]
showTokens t = map show t
--Reduce step, concat the results
combineResults :: [String] -> String
--In haskell, reduce is the foldl function, which takes an operation to fold with, a starting element, and a list to fold on
combineResults strings = foldl concat "" strings
--Finished program
testParser = print (combineResults(showTokens(applyParser tests)))
当然,这只是教学上的。我的实际代码看起来有些不同,并且使用了更多的内部函数(fold concat
因为Haskell已经包含了unlines
该函数,所以不需要[String]->String
。)我的主要观点是,开始时我并不期望使用map / reduce,它只是符合我的需求。我想对列表做一些事情,然后将列表变成单个输出元素。使用map / reduce自然而然。
字符串处理(如解析)是map归约的一种非常明显的用途,映射是对输入文本进行各种转换的应用,并将其还原后将结果文本作为输出再次放回原处。同样,编译器可能类似,使用折叠将抽象语法树元素流转换为更好的形式(优化)。
它是可并行的吗?
任何可并行化的问题本质上都是映射和折叠。相反,贴图步骤本质上是可并行化的(折叠步骤可能取决于折叠的结构),因此这是双向属性。
假设您正在搜索服务器群集,但此时服务器无法响应。mapReduce将要执行的操作是因为它无法访问该树节点到较大的Map,因此它将对其进行重新调度以供以后使用,然后执行Map或Reduce。从本质上讲,它试图确保在环境中软件和硬件的不可预测性下所有信息均可用。