需求:

利用mapReduce实现类似微博中查找共同粉丝的功能。如下:

A:B,C,D,F,E,O
B:A,C,E,K
C:F,A,D,I
D:A,E,F,L
E:B,C,D,M,L
F:A,B,C,D,E,O,M
G:A,C,D,E,F
H:A,C,D,E,O
I:A,O
J:B,O
K:A,C,D
L:D,E,F
M:E,F,G
O:A,H,I,J

求出哪些人两两之间有共同粉丝,及他俩的共同粉丝都是谁。
比如:
A,B  [C,E]

分析:

在利用MapReduce程序解答之前,我们不妨用单机程序练习一下,思路很简单,可以利用两个for循环进行遍历,分别找之间的共同好友,如果有则存到list中,设一个map,key就是两个人的ID,value就是存的list,最后就能求得两个人之间的共同好友。程序如下:

package com.darrenchan.test;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map; public class Test {
public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream(new File("data.txt"));
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
String line = null; // 将文件中的内容存到list中
List<String> list = new ArrayList<String>();
while ((line = br.readLine()) != null) {
list.add(line);
} Map<String, List<String>> map = new LinkedHashMap<>();
// 对list进行处理
for (int i = 0; i < list.size(); i++) {
for (int j = i + 1; j < list.size(); j++) {
//临时的list,用于拼接最后结果中的共同好友
List<String> tempList = new ArrayList<>();
//按照":"进行分割
String keyi = list.get(i).split(":")[0];
String keyj = list.get(j).split(":")[0];
String contenti = list.get(i).split(":")[1];
String contentj = list.get(j).split(":")[1]; //让i层的每一个好友分别和j层的好友找共同好友
String[] fields = contenti.split(",");
for (int k = 0; k < fields.length; k++) {
if (contentj.contains(fields[k])) {
tempList.add(fields[k]);
}
} // 如果tempList里面有内容说明就是有相同元素
if (tempList.size() > 0) {
map.put(keyi + "," + keyj, tempList);
}
}
} // 打印map
for (String key : map.keySet()) {
System.out.println(key + ":" + map.get(key));
}
}
}

求得结果:

A,B [C, E]
A,C [D, F]
A,D [F, E]
A,E [B, C, D]
A,F [B, C, D, E, O]
A,G [C, D, F, E]
A,H [C, D, E, O]
A,I [O]
A,J [B, O]
A,K [C, D]
A,L [D, F, E]
A,M [F, E]
B,C [A]
B,D [A, E]
B,E [C]
B,F [A, C, E]
B,G [A, C, E]
B,H [A, C, E]
B,I [A]
B,K [A, C]
B,L [E]
B,M [E]
B,O [A]
C,D [F, A]
C,E [D]
C,F [A, D]
C,G [F, A, D]
C,H [A, D]
C,I [A]
C,K [A, D]
C,L [F, D]
C,M [F]
C,O [A, I]
D,E [L]
D,F [A, E]
D,G [A, E, F]
D,H [A, E]
D,I [A]
D,K [A]
D,L [E, F]
D,M [E, F]
D,O [A]
E,F [B, C, D, M]
E,G [C, D]
E,H [C, D]
E,J [B]
E,K [C, D]
E,L [D]
F,G [A, C, D, E]
F,H [A, C, D, E, O]
F,I [A, O]
F,J [B, O]
F,K [A, C, D]
F,L [D, E]
F,M [E]
F,O [A]
G,H [A, C, D, E]
G,I [A]
G,K [A, C, D]
G,L [D, E, F]
G,M [E, F]
G,O [A]
H,I [A, O]
H,J [O]
H,K [A, C, D]
H,L [D, E]
H,M [E]
H,O [A]
I,J [O]
I,K [A]
I,O [A]
K,L [D]
K,O [A]
L,M [E, F]

接下来我们思考:如何用MapReduce的程序进行求解呢?

一般如果一个步骤解决不了的问题,我们通常会采用两个步骤来进行求解。在本题中,我们进行思考,让求任意两个人的共同粉丝,那么我们不妨先求得某一个人是哪些人的粉丝,比如:B是A,E,F,G的粉丝,这是第一步我们需要求的。第二步呢?我们就两两配对,AE共同粉丝有B,AF共同粉丝有B,AG共同粉丝有B......然后reduce合并一下即可。

ShareFriendsStepOne.java:

package com.darrenchan.sharefriends;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class ShareFriendsStepOne { public static class ShareFriendsStepOneMapper extends Mapper<LongWritable, Text, Text, Text>{
Text keyText = new Text();
Text valueText = new Text();
/**
* 拿到的数据格式是A:B,C,D,F,E,O
*/
@Override
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
String line = value.toString();
//按照":"进行分割
String person = line.split(":")[0];
String content = line.split(":")[1];
//该person下的所有fans
String[] fans = content.split(",");
valueText.set(person);
for (int i = 0; i < fans.length; i++) {
keyText.set(fans[i]);
context.write(keyText, valueText);
}
}
} public static class ShareFriendsStepOneReducer extends Reducer<Text, Text, Text, Text>{
/**
* 拿到的数据格式是<B,A E F G>,即B是AEFG的粉丝
*/
Text valueText = new Text();
@Override
protected void reduce(Text key, Iterable<Text> values, Context context)
throws IOException, InterruptedException {
StringBuffer sb = new StringBuffer();
for (Text fan : values) {
sb.append(fan).append(",");
}
//最后多了一个“,”,把它消掉
String outFans = sb.substring(0, sb.length()-1); valueText.set(outFans);
context.write(key, valueText);
}
} public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf); job.setJarByClass(ShareFriendsStepOne.class); job.setMapperClass(ShareFriendsStepOneMapper.class);
job.setReducerClass(ShareFriendsStepOneReducer.class); job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class); FileInputFormat.setInputPaths(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1])); System.exit(job.waitForCompletion(true) ? 0 : 1); } }

ShareFriendsStepTwo.java:

package com.darrenchan.sharefriends;

import java.io.IOException;
import java.util.Arrays; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class ShareFriendsStepTwo { public static class ShareFriendsStepTwoMapper extends Mapper<LongWritable, Text, Text, Text> {
Text keyText = new Text();
Text valueText = new Text(); /**
* 拿到的数据格式是A I,K,C,B,G,F,H,O,D 即A是I,K,C,B,G,F,H,O,D的粉丝,然后将后面的两两配对
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String line = value.toString();
String fan = line.split("\t")[0];
String content = line.split("\t")[1];
String[] persons = content.split(","); // 将persons进行排序
Arrays.sort(persons); valueText.set(fan);
for (int i = 0; i < persons.length; i++) {
for (int j = i + 1; j < persons.length; j++) {
keyText.set(persons[i] + "," + persons[j]);
context.write(keyText, valueText);
}
}
}
} public static class ShareFriendsStepTwoReducer extends Reducer<Text, Text, Text, Text> {
/**
* 拿到的数据格式是<AB,C E>,即AB之间的共同粉丝有CE
*/
Text valueText = new Text(); @Override
protected void reduce(Text key, Iterable<Text> values, Context context)
throws IOException, InterruptedException {
StringBuffer sb = new StringBuffer();
sb.append("[");
for (Text fan : values) {
sb.append(fan).append(",");
}
sb.append("]");
//去掉多余的“,”
sb.deleteCharAt(sb.length()-2); valueText.set(sb.toString());
context.write(key, valueText);
}
} public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf); job.setJarByClass(ShareFriendsStepTwo.class); job.setMapperClass(ShareFriendsStepTwoMapper.class);
job.setReducerClass(ShareFriendsStepTwoReducer.class); job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class); FileInputFormat.setInputPaths(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1])); System.exit(job.waitForCompletion(true) ? 0 : 1); } }

求得结果同上:

A,B [E,C]
A,C [D,F]
A,D [E,F]
A,E [D,B,C]
A,F [O,B,C,D,E]
A,G [F,E,C,D]
A,H [E,C,D,O]
A,I [O]
A,J [O,B]
A,K [D,C]
A,L [F,E,D]
A,M [E,F]
B,C [A]
B,D [A,E]
B,E [C]
B,F [E,A,C]
B,G [C,E,A]
B,H [A,E,C]
B,I [A]
B,K [C,A]
B,L [E]
B,M [E]
B,O [A]
C,D [A,F]
C,E [D]
C,F [D,A]
C,G [D,F,A]
C,H [D,A]
C,I [A]
C,K [A,D]
C,L [D,F]
C,M [F]
C,O [I,A]
D,E [L]
D,F [A,E]
D,G [E,A,F]
D,H [A,E]
D,I [A]
D,K [A]
D,L [E,F]
D,M [F,E]
D,O [A]
E,F [D,M,C,B]
E,G [C,D]
E,H [C,D]
E,J [B]
E,K [C,D]
E,L [D]
F,G [D,C,A,E]
F,H [A,D,O,E,C]
F,I [O,A]
F,J [B,O]
F,K [D,C,A]
F,L [E,D]
F,M [E]
F,O [A]
G,H [D,C,E,A]
G,I [A]
G,K [D,A,C]
G,L [D,F,E]
G,M [E,F]
G,O [A]
H,I [O,A]
H,J [O]
H,K [A,C,D]
H,L [D,E]
H,M [E]
H,O [A]
I,J [O]
I,K [A]
I,O [A]
K,L [D]
K,O [A]
L,M [E,F]

MapReduce实战(六)共同粉丝的更多相关文章

  1. Python爬虫实战六之抓取爱问知识人问题并保存至数据库

    大家好,本次为大家带来的是抓取爱问知识人的问题并将问题和答案保存到数据库的方法,涉及的内容包括: Urllib的用法及异常处理 Beautiful Soup的简单应用 MySQLdb的基础用法 正则表 ...

  2. SpringSecurity权限管理系统实战—六、SpringSecurity整合jwt

    目录 SpringSecurity权限管理系统实战-一.项目简介和开发环境准备 SpringSecurity权限管理系统实战-二.日志.接口文档等实现 SpringSecurity权限管理系统实战-三 ...

  3. miniFTP项目实战六

    项目简介: 在Linux环境下用C语言开发的Vsftpd的简化版本,拥有部分Vsftpd功能和相同的FTP协议,系统的主要架构采用多进程模型,每当有一个新的客户连接到达,主进程就会派生出一个ftp服务 ...

  4. 《OD大数据实战》MapReduce实战

    一.github使用手册 1. 我也用github(2)——关联本地工程到github 2. Git错误non-fast-forward后的冲突解决 3. Git中从远程的分支获取最新的版本到本地 4 ...

  5. MapReduce实战:统计不同工作年限的薪资水平

    1.薪资数据集 我们要写一个薪资统计程序,统计数据来自于互联网招聘hadoop岗位的招聘网站,这些数据是按照记录方式存储的,因此非常适合使用 MapReduce 程序来统计. 2.数据格式 我们使用的 ...

  6. mapreduce实战:统计美国各个气象站30年来的平均气温项目分析

    气象数据集 我们要写一个气象数据挖掘的程序.气象数据是通过分布在美国各地区的很多气象传感器每隔一小时进行收集,这些数据是半结构化数据且是按照记录方式存储的,因此非常适合使用 MapReduce 程序来 ...

  7. C# Redis实战(六)

    六.查询数据 在C# Redis实战(五)中介绍了如何删除Redis中数据,本篇将继续介绍Redis中查询的写法. 1.使用Linq匹配关键字查询 using (var redisClient = R ...

  8. MapReduce实战--倒排索引

    本文地址:http://www.cnblogs.com/archimedes/p/mapreduce-inverted-index.html,转载请注明源地址. 1.倒排索引简介 倒排索引(Inver ...

  9. MapReduce实战(三)分区的实现

    需求: 在实战(一)的基础 上,实现自定义分组机制.例如根据手机号的不同,分成不同的省份,然后在不同的reduce上面跑,最后生成的结果分别存在不同的文件中. 对流量原始日志进行流量统计,将不同省份的 ...

随机推荐

  1. DevExpress 中 汉化包 汉化方法

    刚试了一下,直接把汉化包放在 Debug 目录下也是可以的.直接会汉化 第一步: 在Debug 下添加 zh-CN 汉化包(自行下载) 第二步: 在 Program.cs中添加以下代码 : Syste ...

  2. onethink 密码加密方式详解

    /** * 系统非常规MD5加密方法 * @param string $str 要加密的字符串 * @return string */ function think_ucenter_md5($str, ...

  3. STL源码剖析(heap)

    STL heap并不是容器,而是一系列的算法. 这些算法接受RandomAccessIterator[start, end),并将其表述成一棵完全二叉树. 关于heap算法可以参考之前算法导论的一篇博 ...

  4. (转)职责链设计模式(Chain of Responsibility)

    Chain of Responsibility定义Chain of Responsibility(CoR) 是用一系列类(classes)试图处理一个请求request,这些类之间是一个松散的耦合,唯 ...

  5. MySQL的索引及其优化

    前言 索引对查询的速度有着至关重要的影响,理解索引也是进行数据库性能调优的起点.考虑如下情况,假设数据库中一个表有10^6条记录,DBMS的页面大小为4K,并存储100条记录.如果没有索引,查询将对整 ...

  6. 英特尔 Android* 开发者指南上的对等应用

    简单介绍 当没有 Wi-Fi 訪问点或互联网訪问时,Android* 应用可能须要对等连接在两台或多台 Android* 设备之间建立连接. 比方,文件共享应用和多人游戏. 该功能可使用 NFC.蓝牙 ...

  7. 【转】打造自己的视频会议系统 GGMeeting(附送源码)

    原文地址:http://www.cnblogs.com/justnow/p/4487201.html 自从在博客园发布开源即时通信系统GG(QQ高仿版)以来,结识了很多做IM的朋友,然后我和我的伙伴们 ...

  8. linux 常用的命令(转)

    常用指令 ls        显示文件或目录 -l           列出文件详细信息l(list) -a          列出当前目录下所有文件及目录,包括隐藏的a(all) mkdir     ...

  9. 从构建分布式秒杀系统聊聊验证码 给大家推荐8个SpringBoot精选项目

    前言 为了拦截大部分请求,秒杀案例前端引入了验证码.淘宝上很多人吐槽,等输入完秒杀活动结束了,对,结束了...... 当然了,验证码的真正作用是,有效拦截刷单操作,让羊毛党空手而归. 验证码 那么到底 ...

  10. MQTT 学习笔记

    MQTT特点 MQTT协议是为大量计算能力有限,且工作在低带宽.不可靠的网络的远程传感器和控制设备通讯而设计的协议. 1.使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序耦合 2.对负载内容 ...