Mahout架构初探及KMeans算法分布式实现的研究
转载自:http://hi.baidu.com/%B3%CF%D5%F7id/blog/item/6863de395f2f963eb8998fc3.html
1. Mahout简介
Apache项目下的开源的基于hadoop分布式系统的数据挖掘工具,mahout源代码由maven项目管理工具管理。
2. $MAHOUT_HOME/bin/mahout
Mahout启动的shell脚本
几个重要环境变量
JAVA_HOME mahout运行需指定jdk的目录
MAHOUT_JAVA_HOME指定此变量可覆盖JAVA_HOME值
HADOOP_HOME 如果配置,则在hadoop分布式平台上运行,否则单机运行
HADOOP_CONF_DIR指定hadoop的配置文件目录
MAHOUT_LOCAL 如果此变量值不为空,则单机运行mahout。
MAHOUT_CONF_DIR mahout配置文件的路径,默认值是$MAHOUT_HOME/src/conf
MAHOUT_HEAPSIZE mahout运行时可用的最大heap大小
Mahout命令行:
$MAHOUT_HOME/bin/mahout $CLASS [Generic Options] [Job-Specific Options]
Mahout脚本通过调用hadoop在分布式平台运行或调用jre在本地运行,然后调用mahout工程的总入口org.apache.mahout.driver.MahoutDriver类。
3. Mahout总入口org.apache.mahout.driver.MahoutDriver
Mahout启动的总入口做了一下的任务:
1) 首先装载$MAHOUT_CONF_DIR目录下的一个名为driver.classes.props的资源文件(如果找不到,则寻找driver.classes.default.props文件)。
driver.classes.props文件内罗列了mahout内集成的各种工具的资源(Properties)列表,例如列举聚类的KMeans的那一行:
org.apache.mahout.clustering.kmeans.KMeansDriver = kmeans : K-means clustering
等号前面(Properties.Key)的是类名,等号后(Properties.Value)、分号前的是mahout命令行内的简写,分号后面是描述。
2) 装载driver.classes.props中的类。如果mahout命令行第一个参数不是简写,则装载以第一个参数为名的类。
3) 装载“mahout命令行中第一个参数名.props”的配置文件,该配置文件中可以指定输入输出目录等等参数。
4) 调用mahout命令行的第一个参数的类运行,并将命令行参数结合配置文件中的参数以字符的形式传递过去。
4. Kmeans算法的分布式实现
以KMeans为例,org.apache.mahout.driver.MahoutDriver会调用org.apache.mahout.clustering.kmeans.KMeansDriver类。
KMeansDriver类继承于AbstractJob,AbstractJob继承于org.apache.hadoop.conf.Configured并同时实现了org.apache.hadoop.util.Tool接口,
KMeansDriver类提供了KMeans聚类的单机版本和分布式版本。
Main方法里调用了run(String[] args)方法,run(String[] args)方法内对命令行参数做了解析。
根据提供的参数调用单机或分布式的KMeans聚类方法,我们主要研究KMeans聚类方法的分布式算法。
在KMeansDriver类的runIteration方法中,mahout提交了一个MapReduce任务。
这段代码是:
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(ClusterObservations.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Cluster.class);
job.setInputFormatClass(SequenceFileInputFormat.class);
job.setOutputFormatClass(SequenceFileOutputFormat.class);
job.setMapperClass(KMeansMapper.class);
job.setCombinerClass(KMeansCombiner.class);
job.setReducerClass(KMeansReducer.class);
FileInputFormat.addInputPath(job, input);
FileOutputFormat.setOutputPath(job, clustersOut);
job.setJarByClass(KMeansDriver.class);
因此对KMeans算法的分布式实现的研究,我们应主要关注Cluster、ClusterObservations、KMeansMapper、KMeansCombiner、KMeansReducer这几个类。
5. Cluster告诉我们KMeans的cluster是如何表示的。
Cluster继承于org.apache.mahout.clustering.DistanceMeasureCluster类,后者继承于org.apache.mahout.clustering.AbstractCluster抽象类,再后者实现了org.apache.mahout.clustering. Cluster接口
总之,cluster内部有一个变量id(int类型)用于唯一的标识该聚类,numPoints(long类型)表示该聚类内部有多少个点,center(Vector类型,此Vector是数学中的N维向量,也可理解为N维点,非java.util.Vector)表示聚类中心点,radius(Vector类型)表示半径,还有聚合标志位converged(boolean类型)
6. ClusterObservations类
跟Kmeans分布式算法有关,ClusterObservations有s0(double,点数目增量),s1(Vector,用于计算中心点增量),s2(Vector,用于计算半径增量)
7. KMeansMapper
Map过程,输入的key,value =WritableComparable<?> key, VectorWritablepoint
计算每个point表示的点与每个cluster中心center距离,并将改点加入距离最近的cluster中,并计算该cluster的三个增量。
context.write(new Text(nearestCluster.getIdentifier()), new ClusterObservations(1, point, point.times(point)));
输出的key,value = Text, ClusterObservations,key是cluster的id,value是cluster的三个增量(点数目,中心点增量,半径增量)
8. KMeansCombiner
在Map阶段运行结束后,为了减少到Reduce阶段的网络数据输出,mahout对于同一个节点上Map阶段的输出进行合并,把多个相同的key的value合并成一个<Key, Value>。
由于KMeans算法是线性的,因此在此阶段可将Map阶段输出相同key的多个<cluster_id,point.增量>合并成一个<cluster_id, point.总增量>
9. KMeansReducer
Kmeans算法中,有几个cluster聚集就有几个Reducer任务。Reducer任务中,对每个cluster将Map阶段所有的增量计算,重新计算每个cluster的点数,中心点和半径,以及聚合度。