写这个博客的初衷还是想记录一下自己学hadoop的历程啦~,大部分的东西都是老师要我们下来写的作业,虽然自己做的确实不怎么样,但如果要转载的话,还是麻烦注明一下出处,谢谢啦~
(一)问题
老师给我们留的作业就是求一个或多个txt文件中任意两行的距离(余弦、jacard、欧式距离都行),txt文件中每一行是中文英文还是数字都不限。
下面代码的我做测试用的数据格式是这样的:1{s1 s2 s3 s4 s5 s6},前面的1为行号,后面“{”“}”里的内容为真正要计算距离的某一行至,每个值之间用空格隔开。
(二)余弦距离
网上关于余弦距离的计算的也有很多讲解的例子,我同学就举了这样一个例子,比如有这样两行A和B;A为“他喜欢你”,B为“我喜欢你”。要计算A,B的相似度,需先进行中文分词,分次后,A变成了“他” “喜欢” “你”,B为“我” “喜欢” “你”,先求A,B的并集,为{他 喜欢 你 我 },再将A,B转化为向量来表示,如下图所示:
他 | 喜欢 | 你 | 我 | |
A | 1 | 1 | 1 | 0 |
B | 0 | 1 | 1 | 1 |
那么,A对应的向量为(1,1,1,0),B为(0,1,1,1),再根据cosAB=(A,B)/|A||B|求得余弦值。
下面的计算A和B的余弦值的函数cosAB是没有考虑任何的优化直接写的,大家就随便看看吧:
//计算string1和string2的余弦值
public static double calculate(String s1,String s2){
String[] t1=s1.split(" ");
String[] t2=s2.split(" ");
//以键值形式存储m1和m2的值
Map<String, Integer> m1=new HashMap<String, Integer>();
Map<String, Integer> m2=new HashMap<String, Integer>();
for(int i=0;i<t1.length;i++){
if(m1.containsKey(t1[i]))
m1.put(t1[i], m1.get(t1[i])+1);
else
m1.put(t1[i], 1);
}
for(int j=0;j<t2.length;j++){
if(m2.containsKey(t2[j]))
m2.put(t2[j], m2.get(t2[j])+1);
else
m2.put(t2[j], 1);
}
Set temp=new HashSet(t1.length+t2.length);
//set为两个行的并集的key值
for(int i=0;i<t1.length;i++){
for(int j=0;j<t2.length;j++){
temp.add(t1[i]);
temp.add(t2[j]);
}
}
//分别计数
for(int i=0;i<temp.size();i++){
if(! m1.containsKey(temp.toArray()[i]))
m1.put(temp.toArray()[i].toString(), 0);
}
for(int j=0;j<temp.size();j++){
if(! m2.containsKey(temp.toArray()[j]))
m2.put(temp.toArray()[j].toString(), 0);
}
int n1=0,n2=0,nfinal=0;
for(int k=0;k<temp.size();k++){
String st1=temp.toArray()[k].toString();//得到某一个具体的key值
System.out.println("m1的"+st1+"值为:"+m1.get(st1)+" m2的"+st1+"值为:"+m2.get(st1));
n1+=m1.get(st1)*m1.get(st1);
n2+=m2.get(st1)*m2.get(st1);
nfinal+=m1.get(st1)*m2.get(st1);
System.out.println(n1);
System.out.println(n2);
System.out.println(nfinal);
}
double dis=nfinal/Math.sqrt(n1*n2);
return dis;
}
3.1 计算思想
input:
1 s1
2 s2
mapper
1,1 s1
1,2 s1
1,1 s1
2,1 s1
2,1 s2
2,2 s2
1,2 s2
2,2 s2
reducer
1,1 {s1 s1}
1,2 {s1 s2}
2,1 {s1 s2}
2,2 {s2 s2}
input中“1”“2”代表行号。
3.2 mapper函数
public static class calMapper extends Mapper<LongWritable, Text, Text, Text>{//后两个Text指的是CONTEXT的参数3.3 reducer函数
public void map(LongWritable ikey, Text ivalue, Context context) throws IOException, InterruptedException {
String[] temp=ivalue.toString().split(" ");
for(int i=1;i<=100;i++){//偷懒了,这边可以自己确定一下一共有多少行需要计算
String id1=temp[0]+","+i;
String id2=i+","+temp[0];
System.out.println("比较"+id1+"和"+id2);
context.write(new Text(id1), new Text(ivalue));//重要的一点就是context可以写多行
context.write(new Text(id2), new Text(ivalue));
}
}
}
public static class calReducer extends Reducer<Text,Text,Text,Text> {(四)疑问 假如有以下三句话:A{他特别喜欢你};B{他非常喜欢你};C{他不喜欢你}。按照上面的余弦算法,AB和BC的余弦值是一样的,但是直观上感受明显是A比C离B更近,这种情形会怎么处理?
public void reduce(Text key, Iterable<Text> values, Context context ) throws IOException, InterruptedException {
String[] data=new String[2];
String[] k=new String[2];
String[] id1=new String[2];
String[] id2=new String[2];
//将id1,id2的两值分别存于data[0]和data[1]中
int i=0;
for(Text line:values){
String[] temp=line.toString().split(" ");
k[i]=temp[0];
//从values中读取行号和后面的值
data[i]=line.toString().substring(line.toString().indexOf("{")+1, line.toString().length()-1);
/*若将 line.toString().length()-1改为line.toString().indexOf("}"),
就会报index out of range:-1的错误,不是很理解
*/
System.out.println("第"+k[i]+"行的数据为:"+data[i]);
if(i==0){
id1=data[i].split(" ");
}
else{
id2=data[i].split(" ");
}
i++;
}
double dis=calculate(data[0],data[1]);
System.out.println(k[0]+"与"+k[1]+"的相似度为:"+dis);
String t="the similarity of "+k[0]+","+k[1]+"is:";
System.out.println(t+":"+dis);
context.write(new Text(t), new Text(String.valueOf(dis+"\r\n")));
System.out.println("------------------------");
}
}
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。