Map 和 Reduce的概念介绍
MapReduce的创意和灵感来源于函数式编程。map和reduce是函数式编程中两个常用函数。在函数式编程中,map函数对列表的每个元素执行操作或函数。例如,在列表[1, 2, 3, 4]上执行multiple-by-two函数会产生另一个列表[2, 4, 6, 8]。执行这些函数时,原有列表不会被修改。函数式编程认为应当保持数据不可变,避免在多个进程或线程间共享数据。这意味着刚演示过的map函数虽然很简单,却可以通过两个或更多线程在同一个列表上同时执行,线程之间互不影响,因为列表本身没有改变。
与map函数类似,函数式编程中还有一个reduce函数的概念。实际上,reduce在函数式编程中更广为人知的名字是fold函数。reduce或fold函数又称accumulate、compress或者inject函数。reduce或fold函数对数据结构(例如列表)中的所有元素执行一个函数,最终返回单个结果或输出。因此在map函数输出列表[2, 4, 6, 8]上执行reduce求和,会得到单个输出值20。
map和reduce函数可以结合起来处理列表数据,先对列表的每个成员执行一个函数,再对转换生成的列表执行另一个聚合函数。
map和reduce这种简洁的思路可以用在大数据集上,只需稍事修改以适应由元组(tuple)或键值对组成的集合即可。map函数对集合中的每组键值对执行函数并产生一个新集合,接着reduce函数对新生成的集合执行聚合以计算最终结果。一个例子胜过千言万语,下面我通过一个简单的例子来解释整个过程。假设存在由键值对组成的集合:
[{"94303":"Tom"},{"94303":"Jane"},{"94301":"Arun"},{"94302":"Chen"}]
其中键是邮政编码,值是邮编指代范围内居民的姓名。假设在集合上执行某map函数可以获取特定邮编范围内所有居民的姓名,则此map函数输出如下:
[{"94303":["Tom","Jane"]},{"94301":["Arun"]},{"94302":["Chen"]}]
接着对上面的输出执行某reduce函数以计算特定邮编范围内居民的总数,最终输出如下:
[{"94303":2},{"94301":1},{"94302":1}]
与任务并行的概念对比
1.模型应该和多线程类似,几个互相没有依赖的任务独立执行。只是多线程是纵向扩展,MapReduce模型是横向扩展。
2.为了能在不同节点传输数据,必须能序列化。为了更好的实现序列化,因此不用JAVA中实现的数据结构,比如用Text代替String。
适合的场景,可以拆分成若干任务,任务间没有前后依赖关系
1.查询最热门的几个词
- 每个任务先统计词出现的频率
- 把每个任务的统计结果汇总,然后取前K个
2.贝叶斯分类
贝叶斯分类是一种利用概率统计知识进行分类的统计学分类方法。该方法分为两个步骤:训练样本和分类。
可以用是三个MapReduce作业实现。
不适合的场景
前后有依赖关系的场景,比如说最典型的斐波那契数列就不适合。