YongSir

专业程序员伪装者

MapReduce设计思想

so上推荐了一篇通俗的介绍了MapReduce设计思想的文章,简单的做了翻译:
先从一个简单的需求开始,当我们在js中想输出这样的内容时,最直接的方法是使用alert

1
2
alert('apple!');
alert('bannaner!');

但这绝不是一个好的方式,上述代码琐碎绝并且繁琐,那么我们将它封装成一个函数:

1
2
3
4
5
6
function fruit(str) {
alert(str + '!');
}

fruit('apple'); // apple!
fruit('plum'); // plum!

通过将拥有相似功能的代码封装为函数,可以让代码简洁明了
那么如果是下面的情况呢:

1
2
3
4
5
6
7
alert('Tim like:')
fruit('apple')
fruit('plum')

alert('Jerry like:')
fruit('lemmon')
fruit('orange')

比刚才稍微复杂一点儿,但也很容易就能被包装为:

1
2
3
4
5
6
7
8
9
10
11
function someOneDo(someone, f1, f2, f) {
alert(someOne + 'like:')
f(f1)
f(f2)
}

someOneDo('Tim','apple', 'lemmon', fruit);
// 使用匿名函数:
someOneDo('Jerry','lemmon','orange', function(str) {
alert(str + '!');
});

把fruit函数作为一个参数,在someOneDo中调用,这是js中典型的回调。
接下来仿照上述来处理一个根数组有关的问题:

1
2
3
4
5
6
7
var a = [1,2,3]
for(i=0; i<a.length; i++) {
a[i] = a[i] * 2
}
for(i=0; i<a.length; i++) {
a[i] = alert(a[i])
}

分析一下,根上一个例子完全一样,代码类似,都有for循环,都再对元素进行操作,不妨这样:

1
2
3
4
5
6
map(f,arr) {
f(arr)
}

map(function(x){ return x*2}, a);
map(alert, a);

编程中中会有遇到这样的状况,就拿数组来说

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function sum(a)
{
var s = 0;
for (i = 0; i < a.length; i++)
s += a[i];

return s;
}

function join(a)
{
var s = "";
for (i = 0; i < a.length; i++)
s += a[i];

return s;
}

sum元素求和join拼接元素代码是如此的类似,忍不住在抽象一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function reduce(fn, a, init) {
var s = init;
for (i = 0; i < a.length; i++) {
s = fn(s, a[i])
}
return s
}

function sum(a) {
return reduce(function(a, b) { return a+b }, a, 0)
}

function jion(a) {
return reduce(function(a, b) { return a+b}, a, "")
}

这样就把里面的操作封装到了reduce上,现在不管是求和还是拼接都可以通过一个函数来完成了
很多的老旧的语言没办法像这里的js一样把函数置为first class object,比如C/C++中虽然有函数指针,但也做不到这样的简便,很多面向对象的语言干脆不提倡对函数做过多的操作,比如要在Java中这样将函数置为first class object,需要你从头创建一个functor类作为函数基础对象,特别是在数据处理领域内,现代一点的语言都不会自大到–死抱着面向对象可以解决一切问题的谬论。
上述内容多数人看到这里就觉得其实你也没说什么,不过是将函数在抽象了而已,那我们就回到map函数刚刚对数组的操作,看看我们到底能有哪些获益吧!

通过上述map发现:当你对数组元素有任何的操作时,无论数组怎样便利都不会影响结果,你可以从0..last,也可以从last…0,更可以把数组一分为二,一个线程从0…half,另一个线程从half..last,对看到了吗?map对数组的操作整整快了一倍。
现在假设你有成百个上千个分布于世界各地的数据中心,每台机器都运行着微小的map操作,处理一小个小小的数据片段的操作,组合起来的处理能力将使TP,BP级别的,这就为处理大数据问题提供了思路

By abstracting away the very concept of looping, you can implement looping any way you want, including implementing it in a way that scales nicely with extra hardware.

这就是MapReduce处理大数据的核心思想:通过抽象出循环的概念,可以以任何你想要的方式实现循环,同时支持任何程度上的随意扩展额外的硬件添加节点。

参考:
https://www.joelonsoftware.com/2006/08/01/can-your-programming-language-do-this