题目

有两个文件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. Go语言性能优化

    原文:http://bravenewgeek.com/so-you-wanna-go-fast/ 我曾经和很多聪明的人一起工作.我们很多人都对性能问题很痴迷,我们之前所做的是尝试逼近能够预期的(性能) ...

  2. delphi--自带控件(Tcheckbox、TComBobox、TpageControl、TDBGrid,TScrollBox,TEdit)

    一.TCheckBox 使CheckBox选中CheckBox1.Checked := True;选择发生变化 ,OnClick事件if CheckBox1.Checked thenbegin //. ...

  3. Oracle 数据库的组成(instance+database)

    Oracle服务器是一种对象关系数据库管理系统,它为信息管理提供开放.综合.集成的方法. Oracle服务器中有多种进进程.内存结构和文件: Oracle服务器由一个Oracle实例和一个Oracle ...

  4. c# WinForm英雄联盟挂机源码及实现原理

    主要功能:全自动化英雄联盟挂机,游戏中会在原地放技能保持不掉线状态,游戏结束自动重新开始,自动选择英雄,可以晚上挂机刷人机: 缺陷:没怎么完善,如果掉线或者游戏崩溃网络断了软件会自动停止操作,使用时间 ...

  5. pycharm调试scrapy

    pycharm调试scrapy 创建一个run.py文件作为调试入口 run.py中,name是要调试的爬虫的名字(注意,是爬虫类中的name,而不是爬虫类所在文件的名字) 拼接爬虫运行的命令,然后用 ...

  6. BZOJ2648: SJY摆棋子&&2716: [Violet 3]天使玩偶

    BZOJ2648: SJY摆棋子 BZOJ2716: [Violet 3]天使玩偶 BZOJ氪金无极限... 其实这两道是同一题. 附上2648的题面: Description 这天,SJY显得无聊. ...

  7. pandas删除包含指定内容的行

    Outline 处理数据时,遇到文件中包含一些不需要的数据(行),需要把这些不符合要求的行给删除掉. 例如:该数据中应该都是2000年的数据,但是包含了一些2001年的数据,所以需要把2001年的数据 ...

  8. 《深入理解Linux网络技术内幕》阅读笔记 --- 路由表

    路由表基本概念 1.路由是由多个不同的数据结构的组合来描述的,每个数据结构代表路由信息的不同部分.例如,一个fib_node对应一个单独的子网,一个fib_alias对应一条路由.这样做的原因是只需通 ...

  9. Docker Libnetwork Bridge插件实现代码分析----初始化部分

    Bridge driver数据结构如下所示: type driver struct { config *configuration network *bridgeNetwork natChain *i ...

  10. Parcel

    1.IPC解决方案 而非 序列化机制 Container for a message (data and object references) that can be sent through an ...