写这个博客的初衷还是想记录一下自己学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的参数 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> { 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("------------------------"); } }
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。