Skip to content

Commit d75bd88

Browse files
committed
docs:细分 spark MLlib专栏
1 parent 47357f5 commit d75bd88

File tree

4 files changed

+493
-26
lines changed

4 files changed

+493
-26
lines changed

docs/.vuepress/config.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1072,7 +1072,7 @@ module.exports = {
10721072
sidebarDepth: 0,
10731073
children: [
10741074
"01-人工智能概要",
1075-
"GPTs推荐",
1075+
"MapReduce分治思想",
10761076
]
10771077
}
10781078

@@ -1125,6 +1125,14 @@ module.exports = {
11251125
"02-Spark Streaming小试流式处理",
11261126
]
11271127
},
1128+
{
1129+
title: "Spark MLlib",
1130+
collapsable: false,
1131+
sidebarDepth: 0,
1132+
children: [
1133+
"基于Spark的机器学习实践(七)-回归算法",
1134+
]
1135+
},
11281136
],
11291137

11301138
"/md/security/": [{
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# MapReduce分治思想
2+
3+
Google大数据处理的三驾马车:
4+
5+
- MapReduce
6+
- GFS
7+
- Bigtable
8+
9+
在倒排索引、PageRank计算、网页分析等搜索引擎相关的技术中都有大量的应用。
10+
11+
MapReduce本质是分治算法。
12+
13+
## 1 理解分治算法divide and conquer
14+
15+
分而治之:将原问题划分成n个规模较小,并且结构与原问题相似的子问题,递归地解决这些子问题,再合并结果,得到原问题解。
16+
17+
类似递归的定义:
18+
19+
- 分治算法是一种处理问题思想
20+
- 递归是一种编程技巧
21+
22+
分治算法一般都适合用递归实现。分治算法的递归实现中,每层递归都涉及操作:
23+
24+
- 分解:将原问题分解成一系列子问题
25+
- 解决:递归求解各子问题,若子问题够小,则直接求解
26+
- 合并:将子问题结果合并成原问题
27+
28+
分治算法能解决的问题,一般需满足:
29+
30+
- 原问题与分解成的小问题具有相同模式
31+
- 原问题分解成的子问题可以独立求解,子问题之间没有相关性,这一点是分治算法跟动态规划的明显区别,等我们讲到动态规划的时候,会详细对比这两种算法
32+
- 具有分解终止条件,即当问题够小,可直接求解
33+
- 可将子问题合并成原问题,而该合并操作的复杂度不能太高,否则就起不到减小算法总体复杂度的效果了。
34+
35+
## 2 分治算法案例
36+
37+
排序算法中:
38+
39+
- 有序度表示一组数据的有序程度
40+
- 逆序度表示一组数据的无序程度
41+
42+
n个数据,期望从小到大排列,则完全有序的数据的有序度即$n(n-1)/2$,逆序度为0。
43+
倒序排列的数据的有序度就是0,逆序度是$n(n-1)/2$
44+
除了这两种极端,通过计算有序对或者逆序对的个数,来表示数据的有序度或逆序度。
45+
46+
![](/Users/javaedge/Downloads/IDEAProjects/java-edge-master/assets/%E5%88%86%E6%B2%BB%E7%AE%97%E6%B3%95%E6%A1%88%E4%BE%8B.png)
47+
48+
> 如何编程求出一组数据的有序对个数或逆序对个数?
49+
50+
有序对个数和逆序对个数求解方式类似,可只思考逆序对个数的求解方法。
51+
52+
最笨的:
53+
54+
- 拿每个数字跟其后面数字比较,看有几个比它小的。把比它小的数字个数记作k
55+
- 把每个数字都考察一遍后,然后对每个数字对应的k值求和
56+
- 最后得到的总和就是逆序对个数
57+
58+
但这样操作时间复杂度$O(n^2)$,还有更高效的处理方法吗?
59+
60+
分治算法:
61+
62+
- 将数组分成前后两半A1和A2
63+
- 分别计算A1和A2的逆序对个数K1和K2
64+
- 再计算A1与A2之间的逆序对个数K3
65+
- 则数组A的逆序对个数=K1+K2+K3
66+
67+
分治算法其中一个要求是,子问题合并代价不能太大,否则无法降低时间复杂度。那如何快速计算出两个子问题A1与A2之间的逆序对个数?
68+
69+
就要借助归排。
70+
归并排序中有一个非常关键的操作,就是将两个有序的小数组,合并成一个有序的数组。实际上,在这个合并的过程中,我们就可以计算这两个小数组的逆序对个数了。每次合并操作,我们都计算逆序对个数,把这些计算出来的逆序对个数求和,就是这个数组的逆序对个数了。
71+
72+
### 过程代码
73+
74+
```java
75+
private int num = 0; // 全局变量或者成员变量
76+
77+
public int count(int[] a, int n) {
78+
num = 0;
79+
mergeSortCounting(a, 0, n-1);
80+
return num;
81+
}
82+
83+
private void mergeSortCounting(int[] a, int p, int r) {
84+
if (p >= r) return;
85+
int q = (p+r)/2;
86+
mergeSortCounting(a, p, q);
87+
mergeSortCounting(a, q+1, r);
88+
merge(a, p, q, r);
89+
}
90+
91+
private void merge(int[] a, int p, int q, int r) {
92+
int i = p, j = q+1, k = 0;
93+
int[] tmp = new int[r-p+1];
94+
while (i<=q && j<=r) {
95+
if (a[i] <= a[j]) {
96+
tmp[k++] = a[i++];
97+
} else {
98+
num += (q-i+1); // 统计p-q之间,比a[j]大的元素个数
99+
tmp[k++] = a[j++];
100+
}
101+
}
102+
while (i <= q) { // 处理剩下的
103+
tmp[k++] = a[i++];
104+
}
105+
while (j <= r) { // 处理剩下的
106+
tmp[k++] = a[j++];
107+
}
108+
for (i = 0; i <= r-p; ++i) { // 从tmp拷贝回a
109+
a[p+i] = tmp[i];
110+
}
111+
}
112+
```
113+
114+
有些算法确实非常巧妙,并不是每个人短时间都能想到的。比如这个问题,并不是每个人都能想到可以借助归并排序算法来解决,不夸张地说,如果之前没接触过,绝大部分人都想不到。但是,如果我告诉你可以借助归并排序算法来解决,那你就应该要想到如何改造归并排序,来求解这个问题了,只要你能做到这一点,我觉得就很棒了。
115+
116+
分治算法经典问题:
117+
118+
- 二维平面上有n个点,如何快速计算出两个距离最近的点对?
119+
- 有两个n*n的矩阵A,B,如何快速求解两个矩阵的乘积C=A*B?
120+
121+
## 3 分治思想在海量数据处理的应用
122+
123+
数据结构和算法,大部分都是基于内存存储和单机处理。但是,如果要处理的数据量非常大,没法一次性放到内存中,这个时候,这些数据结构和算法就无法工作。
124+
125+
如给10GB的订单文件按照金额排序这样一个需求,看似简单排序,但数据量大10GB,而机器内存可能只有2、3GB,无法一次性加载到内存,也就无法通过单纯快排、归并等基础算法解决。
126+
127+
这种数据量大到内存装不下的问题,就可用分治思想。将海量的数据集合根据某种方法,划为几个小数据集合,每个小数据集合单独加载到内存解决,再将小数据集合合并成大数据集。这种分治处理,不仅克服内存限制,还能利用多线程或多机处理,加快处理速度。
128+
129+
10GB订单排序,先扫描一遍订单,根据订单金额,将10GB文件划为几个金额区间。如订单金额1~100元放到一个小文件,101~200之间放到另一文件。这样每个小文件都可单独加载到内存排序,最后将这些有序小文件合并,就是最终有序的10GB订单数据。
130+
131+
若订单数据存储在类似GFS分布式系统,当10GB订单被划分成多个小文件,每个文件可并行加载到多台机器上处理,再将结果合并,这样并行处理速度也加快。不过,数据存储与计算所在机器是同一或在网络中靠的很近(如一个局域网内,数据存取速度很快),否则就会因为数据访问速度,导致整个处理过程不但不快,反而可能变慢。
132+
133+
## 4 为啥MapReduce本质就是分治思想?
134+
135+
若处理1T、10T、100T,一台机器处理效率非常低。而对谷歌搜索引擎,网页爬取、清洗、分析、分词、计算权重、倒排索引等各环节,都面对如此海量的数据(比如网页)。所以,利用集群并行处理大势所趋。
136+
137+
一台机器过于低效,那就把任务拆分到多台机器处理。若拆分之后小任务之间互不干扰,独立计算,再将结果合并。这不就是分治思想?
138+
139+
MapReduce框架只是一个任务调度器,底层依赖GFS来存储数据,依赖Borg管理机器。它从GFS中拿数据,交给Borg中的机器执行,并且时刻监控机器执行的进度,一旦出现机器宕机、进度卡壳等,就重新从Borg中调度一台机器执行。
140+
141+
尽管MapReduce的模型非常简单,但是在Google内部应用非常广泛。它除了可以用来处理这种数据与数据之间存在关系的任务,比如MapReduce的经典例子,统计文件中单词出现的频率。除此之外,它还可以用来处理数据与数据之间没有关系的任务,比如对网页分析、分词等,每个网页可以独立的分析、分词,而这两个网页之间并没有关系。网页几十亿、上百亿,如果单机处理,效率低下,我们就可以利用MapReduce提供的高可靠、高性能、高容错的并行计算框架,并行地处理这几十亿、上百亿的网页。
142+
143+
## 5 总结
144+
145+
分而治之:将原问题划分成n个规模较小而结构与原问题相似的子问题,递归地解决这些子问题,然后再合并其结果,就得到原问题的解。这个思想非常简单、好理解。
146+
147+
分治算法的典型的应用场景:
148+
149+
- 指导编码,降低问题求解的时间复杂度
150+
- 解决海量数据处理问题。如MapReduce本质就是利用分治思想

0 commit comments

Comments
 (0)