持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第8天
一、算法说明
由图所示,我们先简单假设一个朋友圈,下面是好友之间的关系。
判断某两个人是否认识,并推荐为好友,并且某两个非好友的用户,他们的共同好友越多,那么他们越可能认识。
1、直接相连的表示两个人是好友关系。 2、两个人有相同的好友表示两个人是间接好友。 3、好友推荐列表就是按照两个用户的共同好友数量排名。
二、思路分析
1、推荐者与被推荐者一定有一个或多个相同的好友
2、全局去寻找好友列表中两两关系
3、去除直接好友
4、统计两两关系出现次数
三、详细步骤
3、1 数据准备:
每行首位为用户本人,后面的为其对应好友
注:每个名字之间有且只有一个空格分割
3、2 编码操作:
3、2、1 创建项目
3、2、2 代码编写
- FriendsRecommend.java
package org.hadoop.friend;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
public class FriendsRecommend {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
job.setJarByClass(FriendsRecommend.class);
Path input = new Path(args[0]);
FileInputFormat.addInputPath(job, input);
Path output = new Path(args[1]);
//如果文件存在,,删除文件,方便后续调试代码
if (output.getFileSystem(conf).exists(output)) {
output.getFileSystem(conf).delete(output,true);
}
FileOutputFormat.setOutputPath(job, output);
job.setMapperClass(FriendsRecommendMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
job.setReducerClass(FriendsRecommendReduce.class);
job.waitForCompletion(true);
}
}
- FriendsRecommendMapper.java
package org.hadoop.friend;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.util.StringUtils;
import java.io.IOException;
public class FriendsRecommendMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
Text mkey = new Text();
IntWritable mval = new IntWritable();
@Override
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
//不能用双引号,要用单引号 将传递过来的值进行分割
String[] strs = StringUtils.split(value.toString(), ' ');
// 直接好友的 key为直接好友列表 value为0
for (int i = 1; i < strs.length; i++) {
//直接好友关系
mkey.set(fof(strs[0], strs[i]));
mval.set(0);
context.write(mkey, mval);
//间接好友关系 设置value为1
for (int j = i + 1; j < strs.length; j++) {
mkey.set(fof(strs[i], strs[j]));
mval.set(1);
context.write(mkey, mval);
}
}
}
//两个共同好友的间接好友之间,可能存在 B C 和C B 的情况,但是比对累加时,计算机不识别,所以需要字典排序
private static String fof(String str1, String str2) {
//compareTo比较的 正数说明大
if (str1.compareTo(str2) > 0) {
return str2 + ":" + str1;
}
return str1 + ":" + str2;
}
}
- FriendsRecommendReducer.java
package org.hadoop.friend;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
class FriendsRecommendReduce extends Reducer<Text, IntWritable, Text, IntWritable> {
IntWritable rval = new IntWritable();
@Override
protected void reduce(Text key, Iterable<IntWritable> vals,Context context)
throws IOException, InterruptedException {
int sum=0;
for (IntWritable v : vals) {
//发现直接是0的 是直接好友 舍弃
if (v.get() ==0 ) {
return ;
}
sum +=1;
}
rval.set(sum);
context.write(key, rval);
}
}
3、2、3 程序打包
- 在父项目的maven视图下点击package进行打包
- 打包成功后可以获得jar包
3、2、4 程序测试
cd /opt/testData/friend 进入friend文件,若没有testData 、friend文件夹可自行创建
- 开启Hadoop集群
- 把jar包上传到虚拟机node01里
- 上传本地测试文件hello.txt到虚拟机
分布式文件系统创建input目录并且input目录上传测试文件friend.txt,执行程序
- 查看结果