Hadoop的安装、测试、以及为伪分布式下矩阵乘法的实现
1 Hadoop的安装
(1)运行环境:
Linux环境:Ubuntu13.04
Hadoop安装包:hadoop-1.1.2.tar
(2)安装主要分为以下几个步骤:( 以root登录linux )
①安装SSH,输入如下命令:
apt-get install ssh
②安装JAVA环境,输入如下命令:
apt-get install sun-java6-jdk
这条命令将自动完成java包的下载、安装以及环境变量配置,安装完成之后,直接在命令行下输入java测试JDK环境是否已成功搭建,若成功,则如下图1-1所示:
图1-1 java环境测试
另外,可通过输入java –version来查看java的版本号,如图1-2所示:
图1-2 查看JAVA版本号
③安装Hadoop安装包:
首先将Hadoop的安装包复制到/usr目录下,然后在终端中输入命令解压
tar -xzvf hadoop-1.1.2.tar
然后是在Hadoop中配置java环境,及加入JAVA_HOME的目录地址,具体是修改conf/hadoop-env.sh文件,加入一行:
exportJAVA_HOME=/usr/lib/jvm/java-6-sun-1.6.0.06
也就是JAVA安装包默认的安装位置。
④在默认模式(单机模式下),测试Hadoop是否能正确运行,这里使用测试包中的WordCount类来测试:
具体如下:(在解压后的hadoop-1.1.2文件夹目录下)
创建输入文件夹input,并创建两个输入文件test1.txt和text2.txt,如下:
mkdirinput
cdinput
echo“hello we are one world”>test1.txt
echo“we are young one world”>test2.txt
然后运行WordCount实例:
bin/hadoop jarhadoop-examples-1.1.2.jar wordcount input output
运行完了之后,可输入如下命令查看输出信息:
cat output/*
结果如下图1-3所示:
图1-3 默认模式下wordcount实例输出
(3)伪分布式模式下的配置和wordcount实例运行
①修改conf/ 目录下以下三个文件的参数,具体如下图1-4、1-5和1-6所示:
图1-4 core-site.xml文件
图1-5 hdfs-site.xml文件
图1-6 mpared-site.xml文件
②免密钥SSH设置:
cd 到~/,先创建文件夹 .ssh ,然后生成密钥对:
ssh-keygen -t rsa 一直按Enter,选择默认设置
之后进入.ssh目录,复制密钥对:
cp id_rsa.pub anthorized_keys
③运行wordcount实例过程:
格式化分布式文件系统:(当前目录是hadoop-1.1.2)
bin/hadoop namenode –format
启动Hadoop守护进程:
bin/start-all.ssh
启动后,可输入jps命令查看当前所有java进程,如下图1-7所示:
图1-7 jps命令显示当前JAVA进程
运行wordcount实例:
由于是分布式,需要把本地输入文件夹input拷贝到HDFS下,这里创建in文件夹,就拷到这:
bin/hadoopfs -copyFromLocal input in
然后就调用实例包来运行wordcount实例,注意这是分布式,输出结果也在HDFS端:
bin/hadoopjar hadoop-examples-1.1.2.jar wordcount in out
执行完了之后,如下图1-8所示:
图1-8 运行情况
然后查看输出结果,输入bin/hadoop fs -cat out/* ,如下图1-9所示:
图1-9 查看运行输出结果
2 利用Hadoop实现矩阵乘法
(1)编程思路:
采用的是MapReduce的并行编程方法,MapReduce 的计算过程简而言之,就是将大数据集分解为成百上千的小数据集,每个(或若干个)数据集分别由集群中的一个结点(一般就是一台普通的计算机)进行处理并生成中间结果,然后这些中间结果又由大量的结点进行合并, 形成最终结果。其模型如下图2-1所示:
图2-1MapReduce并行计算模型
计算模型的核心是 Map 和 Reduce 两个函数,这两个函数由用户负责实现,功能是按一定的映射规则将输入的<key, value> 对转换成另一个或一批 <key, value> 对输出。
在矩阵乘法中,只有在第一个矩阵的列数和第二个矩阵的行数相同时才有定义。一般单指矩阵乘积时,指的便是一般矩阵乘积。若M为i×r矩阵,N为r×j矩阵,则他们的乘积M·N会是一个i×j矩阵。其乘积矩阵的元素如下式2-1得出:
(2)实现过程:
对矩阵乘法的MapReduce实现方法是:
①Map函数:对于矩阵M的每个元素M[i,j],产生一系列的键值对:
(i,k)--> ( M , j , M[ i , j ] )
其中k=1,2…,直到矩阵N的列数。
同样,对于矩阵N的每个元素N[j,k],产生一系列的键值对:
( i , k) ->( N , j , N[ j , k ])
其中i=1,2…,直到矩阵M的行数。
②Reduce函数:根据MapReduce的原理,相同键i,k的数据会发送个同一个reduce。
例如:
如果M为2*2矩阵,N为2×3矩阵,reduce函数需要处理的数据为: (1,1)-> [(M,1,M[1,1])、(M,2, M[1,2])、(N,1, N[1,1])、(N,2, N[2,1])],
(1,2)->[(M,1,M[1,1])、(M,2, M[1,2])、(N,1, N[1,2])、(N,2, N[2,2])],
(1,3)->[(M,1,M[1,1])、(M,2, M[1,2])、(N,1, N[1,3])、(N,2,N[2,3])],
(2,1)-> [(M,1,M[2,1])、(M,2, M[2,2])、(N,1, N[1,1])、(N,2, N[2,1])],
(2,2)-> [(M,1,M[2,1])、(M,2, M[2,2])、(N,1, N[1,2])、(N,2, N[2,2])],
(2,3)-> [(M,1,M[2,1])、(M,2, M[2,2])、(N,1, N[1,3])、(N,2, N[2,3])]。
这样只要将所有(M,j, M[i,j])和(N,j, N[j,k])分别按照j值排序并放在不同的两个列表里面。将这个列表的第j个元素M[i,j]个N[j,k]相乘,然后将这些积相加,最后积的和与键(i,k)组对作为reduce函数的输出。对于上面的例子reduce的输出就是:
(1,1)->(M[1,1]*N[1,1]+ M[1,2]* N[2,1])
(1,2)->(M[1,1]*N[1,2]+ M[1,2]* N[2,2])
(1,3)->(M[1,1]*N[1,3]+ M[1,2]* N[2,3])
(2,1)->(M[2,1]*N[2,1]+ M[2,2]* N[2,1])
(2,2)->(M[2,1]*N[1,2]+ M[2,2]* N[2,2])
(2,3)->(M[2,1]*N[1,3]+ M[2,2]* N[2,3])
(3)具体代码实现如下: 【MartrixMultiplication.java】
来自网站:https://github.com/intergret/snippet/blob/master/MartrixMultiplication.java
importjava.io.IOException;
importorg.apache.hadoop.conf.Configuration;
importorg.apache.hadoop.fs.Path;
importorg.apache.hadoop.io.Text;
importorg.apache.hadoop.mapreduce.Job;
importorg.apache.hadoop.mapreduce.Mapper;
importorg.apache.hadoop.mapreduce.Reducer;
importorg.apache.hadoop.mapreduce.lib.input.FileInputFormat;
importorg.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
importorg.apache.hadoop.util.GenericOptionsParser;
publicclass MartrixMultiplication{
public static class MartrixMapper extends Mapper<Object,Text, Text, Text>{
private Text map_key = new Text();
private Text map_value = new Text();
int rNumber = 50;
int cNumber = 50; //一个50*50的矩阵
String fileTarget;
String i, j, k, ij, jk;
public void map(Object key, Text value,Context context) throws IOException, InterruptedException { //Map函数
String eachterm[] =value.toString().split("#");
fileTarget = eachterm[0];
if(fileTarget.equals("M"))
{
i = eachterm[1];
j = eachterm[2];
ij = eachterm[3];
for(int c = 1; c<=cNumber; c++)
{
map_key.set(i + "#" +String.valueOf(c));
map_value.set("M" +"#" + j + "#" + ij);
context.write(map_key,map_value);
}
}
elseif(fileTarget.equals("N"))
{
j = eachterm[1];
k = eachterm[2];
jk = eachterm[3];
for(int r = 1; r<=rNumber; r++)
{
map_key.set(String.valueOf(r) +"#" +k);
map_value.set("N" +"#" + j + "#" + jk);
context.write(map_key,map_value);
}
}
}
}
public static class MartrixReducer extendsReducer<Text,Text,Text,Text> {
private Text reduce_value = new Text();
int jNumber = 50;
int M_ij[] = new int[jNumber+1];
int N_jk[] = new int[jNumber+1];
int j, ij, jk;
String fileTarget;
intjsum = 0;
public void reduce(Text key,Iterable<Text> values, Context context) throws IOException,InterruptedException { //reduce函数
jsum = 0;
for (Text val : values)
{
String eachterm[] =val.toString().split("#");
fileTarget = eachterm[0];
j = Integer.parseInt(eachterm[1]);
if(fileTarget.equals("M"))
{
ij= Integer.parseInt(eachterm[2]);
M_ij[j]= ij;
}
elseif(fileTarget.equals("N")){
jk= Integer.parseInt(eachterm[2]);
N_jk[j]= jk;
}
}
for(int d = 1; d<=jNumber; d++)
{
jsum += M_ij[d] * N_jk[d];
}
reduce_value.set(String.valueOf(jsum));
context.write(key, reduce_value);
}
}
public static void main(String[] args) throwsException { //main函数入口
Configuration conf = new Configuration();
String[] otherArgs = newGenericOptionsParser(conf, args).getRemainingArgs();
if (otherArgs.length != 2) {
System.err.println("Usage:MartrixMultiplication <in> <out>");
System.exit(2);
}
Job job = new Job(conf,"martrixmultiplication");
job.setJarByClass(MartrixMultiplication.class);
job.setMapperClass(MartrixMapper.class);
job.setReducerClass(MartrixReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
FileInputFormat.addInputPath(job, newPath(otherArgs[0]));
FileOutputFormat.setOutputPath(job, newPath(otherArgs[1]));
System.exit(job.waitForCompletion(true) ?0 : 1);
}
}
(4)编译运行过程:
由于伪分布式环境下,节点性能有限,尤其是跑在虚拟机环境下,试了一下跑500*500的矩阵,Map到66%左右就发现虚拟机硬盘爆了,所以,为了测试算法的正确性,下面使用50*50的矩阵来运行。只要算法是恰当的,数据规模可以随硬件支持程度而改变。
首先把源文件编译生成MartrixMultiplication.jar,需要调用以下两个包:
/usr/hadoop-core-1.1.2.jar
/usr/hadoop-1.1.2/lib/commons-cli-1.2.jar
①在缺省目录(/usr/hadoop-1.1.2/)下,把MartrixMultiplication.java文件放在一个新的文件夹local_matrix下(文件夹的名称随意,这个只是方便记忆,),然后把测试数据文件M.data放在另外一个新的文件夹input2下;
M.data中的数据形式为:(一行一个数据)
M#a#b#c 表示M矩阵第a行第b列的值是c;
M#a#b#c 表示N矩阵第a行第b列的值是c;
编译MartrixMultiplication.java文件,生成class文件:
javac -classpathhadoop-core-1.1.2.jar:lib/commons-cli-1.2.jar
-d local_matrix local_matrix/MartrixMultiplication.java
打包发布,生成MartrixMultiplication.jar文件:
jar -cvflocal_matrix/MartrixMultiplication.jar -C local_matrix/ .
②把输入文件从本地拷贝到HDFS:
bin/hadoop fs -copyFromLocal input2in2
③运行jar包
bin/hadoop jarlocal_matrix/MartrixMultiplication.jar
MartrixMultiplicationin2 out2
运行过程如下图2-2所示:
图2-2 运行过程
④对于HDFS,其运行结果输出到了指定的文件夹out2中,要想在本地看到,还得从HDFS中拷贝出来:
bin/hadoop fs -get out2 output2
⑤然后,在本地查看输出的矩阵相乘的结果,既可以直接打开output2文件夹看里面的输出文档part-r-00000,也可以输入下面的命令:
cat output2/*
在本次实验中,输入的测试数据是两个50*50,每行每列的值都是1的矩阵,所以按照理论上来说,应该输出一个50*50,每行每列都是50的矩阵,实际输出如下图2-3所示(一部分截图):
图2-3 输出结果
由输出结果可知,本次计算是与理论相符和,也证明了这个算法的正确性。之后可通过修给代码和输入文件实现大规模数据的运算。此外,也可以配置完全分布式方式来运行。
*******Workpiece By Henry ******