一些开源的软件项目提供了海量数据处理的解决方案,其中一个项目就是Hadoop,它采用java语言编写,支持在大量机器上分布式处理数据。
15.1 MapReduce:分布式计算的框架
优点:可以在短时间内完成大量工作
缺点:算法必须经过重写,需要对系统工程有一定的理解
一个作业即把一个MapReduce程序应用到一个数据集上。
- MapReduce在大量节点组成的集群上运行。它的工作流程是:单个作业被分成很多小份,输入数据也被切片分发到每个节点,各个节点只在本地数据上做运算,对应的运算代码称为mapper,这个过程被称作map阶段。每个mapper的输出通过某种方式组合(一般还会做排序).排序后的结果再被分成小份分发到各个节点进行下一步处理工作。第二步的处理阶段被称为reduce阶段,对应的代码称为Reducer.Reducer的输出就是程序的最终执行结果。
- Map Reduce的优势在于,它使得程序以并行方式执行。每个mapper产生一个结果,最后一个redecer来比较所有Mapper的输出。
在任何时候,**每个mapper或reducer之间都不进行通信。**每个节点只处理自己的事务,且在本地分配的数据集上运算。 - 不同类型的作业可能需要不同数目的reducer.MapReduce的框架中还有其他一些灵活的配置选项。MapReduce的整个编配工作由主节点(master node)控制。这些主节点控制整个MapReduce作业编配,包括每份数据存放的节点位置,以及map,sort和reduce等阶段的时序控制等。此外,主节点还要半酣容错机制。一般地,每份mapper的输入数据会同时分发到多个节点形成多份副本,用于事务的失效处理。每个节点必须与主节点通信,表明自己工作正常。
总结一下上面的关于MapReduce的学习要点:
1)主节点控制mapreduce的作业流程
2)mapreduce的作业可以分成map任务和reduce任务
3)map任务之间不做数据交流,reduce任务也一样
4)在Map和reduce阶段中间,有一个sort或combine阶段
5)数据被重复存放在不同的机器上,以防某个机器失效
6)mapper和reducer传输的数据形式为key/value对
15.2 Hadoop流
hadopp流很像linux系统中的管道(管道使用符号|,可以将一个命令的输出作为另一个命令的输入)。如果用mapper.py调用mapper,用reducer.py调用reducer,那么Hadoop流就可以像Linux命令一样执行。如:
cat inputFile.txt|python3 mapper.py|sort|python3 reducer.py
15.2.1 分布式计算均值和方差的mapper
接下来我们将构建一个海量数据上分布式计算均值和方差的Map Reduce作业。
from numpy import mat,mean,power
import sys
#分布式均值和方差计算的mapper
def readInput(file):
for line in file:
yield line.strip()
if __name__ == '__main__':
inputWs = readInput(sys.stdin)
inputW = [float(line) for line in inputWs]
numInputs = len(inputW)
inputW = mat(inputW)
sqInput = power(inputW,2)
print('%d\t%f\t%f'%(numInputs,mean(inputW),mean(sqInput)))
#一个好的习惯是向标准错误输出发送报告。如果某作业10分钟内没有报告输出,则将被Hadoop终止
print('>>',sys.stderr,'report:still alive')
Linux下输入:
cat inputFile.txt|python3 mrMeanMapper.py
Windows下输入:
python mapreduce.py < inputFile.txt
15.2.2 分布式计算均值和方差的reducer
很多Mapper是并行执行的,所以需要将这些mapper的输出合并成一个值。接下来给出reducer的代码:将中间的key/value对进行组合
from numpy import mat,mean,power
import sys
#分布式均值和方差计算的mapper
def readInput(file):
for line in file:
yield line.rstrip()
"""接受mapper的输出,并将它们合并成为全局的均值和方差"""
input = readInput(sys.stdin)
mapperOut = [line.split('\t') for line in input]
cumVal = 0.0
cumSumSq = 0.0
cumN = 0.0
for instance in mapperOut:
nj = float(instance[0])
cumN += nj
cumVal += nj*float(instance[1])
cumSumSq += nj*float(instance[2])
mean = cumVal/cumN
varSum = (cumSumSq - 2*mean*cumVal + cumN*mean*mean)/cumN
print('%d\t%f\t%f' % (cumN,mean,varSum))
print('>>',sys.stderr,'report:still alive')
15.3 MapReduce上的机器学习
简单贝叶斯——它属于为数不多的可以很自然地使用MapReduce的算法。在Mapreduce中计算加法非常容易,而简单贝叶斯正需要统计某个类别下某特征的概率。因此可以将每个指定类别下的计算作业交由单个的mapper处理,然后使用reducer来将结果加和。
K-近邻算法——该算法首先试图在数据集上找到相似向量,即便数据集很小,这个步骤也将花费大量的时间。在海量数据下,它将极大地影响欸长商业周期的运转。一个提速的办法是构建树来存储数据,利用树形结构来缩小搜索范围。该方法是在特征数小于10的情况下效果很好。高维数据(如文本、图像)流行的近邻查找方法是局部敏感哈希算法。
支持向量机(SVM)——第6章使用的platt SMO算法很难实现,但一个近似的SVM算法叫做最邻近支持向量机(proximal SVM),求解更快并且易于在MapReduce框架下实现
奇异值分解——lanczos算法是一个有效的求解近似特征值的算法。
K-means算法——一个流行的分布式聚类方法叫做canopy聚类,可以先调用canopy聚类法取得初始的k个簇,然后再运行K-means聚类方法。