题目

有两个文件A和B,两个文件中都有几百万行数字,现在需要找出A文件和B文件中数字集合的交集、并集、以及A对B的差集。

简单说一下思路:

这个问题关键在于key和value的设计。这里我将文件中的数字设置为key,将文件名称设置为value。这样在reduce阶段很容易就能找出A、B两个文件中数字的交并差集了。

并集就是reduce阶段能输出的全部记录;交集则需要做下过滤,即一个记录中的value需要同时有A、B两个文件的名称;差集则是文件名称集合中只包含A或B的记录。

看下用MapReduce是如何实现的:

package com.zhyea.dev;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.NullWritable;
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.input.FileSplit;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import java.io.IOException;
import java.util.Iterator; public class ContentCompare { public static class SplitterMapper extends Mapper<Object, Text, Text, Text> { private Text text = new Text(); @Override
public void map(Object key, Text value, Context context) {
try {
String fileName = ((FileSplit) context.getInputSplit()).getPath().getName();
text.set(fileName);
context.write(value, text);
} catch (Exception e) {
e.printStackTrace();
}
}
} public static class UnionReducer extends Reducer<Text, Text, Text, NullWritable> {
@Override
public void reduce(Text key, Iterable<Text> values, Context context) {
try {
context.write(key, NullWritable.get());
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static class InterReducer extends Reducer<Text, Text, Text, NullWritable> {
@Override
public void reduce(Text key, Iterable<Text> values, Context context) {
try {
Iterator<Text> itr = values.iterator();
boolean flagA = false;
boolean flagB = false;
while (itr.hasNext()) {
String s = itr.next().toString();
if (s.equals("B")) {
flagB = true;
}
if (s.equals("A")) {
flagA = true;
}
}
if (flagA && flagB) {
context.write(key, NullWritable.get());
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static class DiffAReducer extends Reducer<Text, Text, Text, NullWritable> {
@Override
public void reduce(Text key, Iterable<Text> values, Context context) {
try {
Iterator<Text> itr = values.iterator();
boolean flagA = false;
boolean flagB = false;
while (itr.hasNext()) {
String s = itr.next().toString();
if (s.equals("A")) {
flagA = true;
}
if (s.equals("B")) {
flagB = true;
}
}
if (flagA && !flagB) {
context.write(key, NullWritable.get());
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException { Configuration conf = new Configuration(); Job job = Job.getInstance(conf, "content-compare");
job.setJarByClass(ContentCompare.class); job.setMapperClass(SplitterMapper.class);
job.setReducerClass(DiffAReducer.class); job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class); job.setOutputKeyClass(Text.class);
job.setOutputValueClass(NullWritable.class); job.setNumReduceTasks(1); FileInputFormat.addInputPath(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1])); System.exit(job.waitForCompletion(true) ? 0 : 1);
} }

用spark实现就简单的多了,这里我们很大程度上是受益于scala语法的简洁性:

package com.talkingdata.campaign

import org.apache.hadoop.io.{LongWritable, Text}
import org.apache.hadoop.mapred.{FileSplit, InputSplit, TextInputFormat}
import org.apache.spark.rdd.HadoopRDD
import org.apache.spark.{SparkConf, SparkContext} object ContentCompare { def main(args: Array[String]): Unit = { val inputPath = args(0)
val outputPath = args(1)
val conf = new SparkConf().setAppName("content compare")
val sc = new SparkContext(conf) val data = sc.hadoopFile[LongWritable, Text, TextInputFormat](inputPath)
val hadoopRDD = data.asInstanceOf[HadoopRDD[LongWritable, Text]] hadoopRDD.mapPartitionsWithInputSplit[(String, String)](readFile)
.reduceByKey(_ + _)
.filter(p => p._2.length == 2)
.map(p => p._1)
.repartition(1)
.saveAsTextFile(outputPath) def readFile(inputSplit: InputSplit, itr: Iterator[(LongWritable, Text)]) = {
val fileName = inputSplit.asInstanceOf[FileSplit].getPath.getName
itr.map(p => (p._2.toString, fileName))
} } }

上面的代码中列出了计算交集的方法。并集实在是没什么好说的,读取文件后,reduce或distinct一下就能实现了。

要计算差集的话只需要调整下filter中的函数值就可以了:

hadoopRDD.mapPartitionsWithInputSplit[(String, String)](readFile)
.reduceByKey(_ + _)
.filter(p => p._2.length == 1 && p._2 == "A")
.map(p => p._1)
.repartition(1)
.saveAsTextFile(outputPath)

#############

十二道MR习题 - 3 - 交集并集差集的更多相关文章

  1. 十二道MR习题 - 2 - 多文件保存

    题目: 需要将MR的执行结果保存到3个文件中,该怎么做. 又是一个送分题. 对于Hadoop的MapReduce来说只需要设置一下reduce任务的数量即可.MR的Job默认reduce数量是1,需要 ...

  2. 十二道MR习题 - 4 - TopN问题

    题目: 有一个很大的文件,这文件中的内容全部都是数字,要求尝试从这个文件中找出最大的10个数字. 分析: 看起来像是一个比较简单的问题.不用大数据框架的话,也能比较轻易的实现:就是逐个读取文件中的每个 ...

  3. 十二道MR习题 – 1 – 排序

    题目: 一个文件,大小约为100G.文件的每一行都是一个数字,要求对文件中的所有数字进行排序. 对于这个题目,了解过Hadoop的同学可以笑而不语了.即使用spark实现也是非常简单的事情. 先说下如 ...

  4. (java/javascript) list 交集 并集 差集 去重复并集

    java list 交集 并集 差集 去重复并集 package com; import java.util.ArrayList; import java.util.Iterator; import ...

  5. Python 求两个文本文件以行为单位的交集 并集 差集

    Python 求两个文本文件以行为单位的交集 并集 差集,来代码: s1 = set(open('a.txt','r').readlines()) s2 = set(open('b.txt','r') ...

  6. 如何求ArrayList集合的交集 并集 差集 去重复并集

    需要用到List接口中定义的几个方法: addAll(Collection<? extends E> c) :按指定集合的Iterator返回的顺序将指定集合中的所有元素追加到此列表的末尾 ...

  7. spark之交集并集差集拉链

    spark之交集并集差集拉链 def main(args: Array[String]): Unit = { val sparkConf = new SparkConf().setMaster(&qu ...

  8. java 两个list 交集 并集 差集 去重复并集

    前提需要明白List是引用类型,引用类型采用引用传递. 我们经常会遇到一些需求求集合的交集.差集.并集.例如下面两个集合: List<String> list1 = new ArrayLi ...

  9. java list 交集 并集 差集 去重复并集

    package com; import java.util.ArrayList;import java.util.Iterator;import java.util.List; public clas ...

随机推荐

  1. 穿透Session 0 隔离(一)

    服务(Service)对于大家来说一定不会陌生,它是Windows 操作系统重要的组成部分.我们可以把服务想像成一种特殊的应用程序,它随系统的“开启-关闭”而“开始-停止”其工作内容,在这期间无需任何 ...

  2. event chrome firefox 获取点击对象的 id 类

    <!doctype html><html lang="en"><head> <meta charset="UTF-8" ...

  3. android问题总结

    1.当打开eclipse时出现如下窗口(内容如下) Error when loading the SDK: Error: Error parsing \Android\adt-bundle-windo ...

  4. [luogu4234]最小差值生成树

    [luogu4234]最小差值生成树 luogu 从小到大枚举边,并连接,如果已连通就删掉路径上最小边 lct维护 \(ans=min(E_{max}-E_{min})\) #include<b ...

  5. PHP获取客户端的IP

    function getClientIP(){    global $ip;    if (getenv("HTTP_CLIENT_IP"))        $ip = geten ...

  6. 003-linux安装软件的几种方法

    一.rpm包安装方式步骤 1.找到相应的软件包,比如soft.version.rpm,下载到本机某个目录: 2.打开一个终端,su -成root用户: 3.cd soft.version.rpm所在的 ...

  7. redis的图形化工具(四)

    1. 介绍 本篇会介绍几个关于redis的图形化的监控工具和管理工具. 2. redis-stat redis-stat提供终端和web端的监控页面,它安装和使用起来很简单. 安装只需要一条指令. $ ...

  8. CoreThink开发(十三)增加页面加载动画

    效果: 加载动画是由jquery和fakeloader这个js库实现的. 其实这个也可以做成一个插件,用数据库记录是否开启,选择动画的样式,那样扩展性会更好. 源码资源已经上传在我的csdn下载中. ...

  9. 吴超老师课程--Flume的安装和介绍

    常用的分布式日志收集系统

  10. delphi webbrowser post自动登录

    delphi webbrowser post自动登录     var  EncodedDataString: WideString;  PostData: OleVariant;  Headers: ...