题目

有两个文件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. angular的过滤器

    angular有一些自带的过滤器,今天我就来写一下. 首先还是先把导入一个angular插件,再在我们的js中把模块和控制台写上(别忘了在html中写入模块名和在body中写入控制台名,当然控制台名可 ...

  2. Java——BeanUtils基本用法

    为了操作JavaBean的属性,sun公司自己写了一套内省的api(在Java.beans.*)中,但是我们发现操作起来还是比较复杂的,所以apache公司就自己写了一套api替代了它,大大方便了开发 ...

  3. ChannelOption用到的socket的标准参数

    ChannelOption.SO_BACKLOG, 1024 BACKLOG用于构造服务端套接字ServerSocket对象,标识当服务器请求处理线程全满时,用于临时存放已完成三次握手的请求的队列的最 ...

  4. express, mocha, supertest,istanbul

    引子 有群友问到Express怎么做 单元测试/覆盖率测试,这是上篇所遗漏的,特此补上 Express Web测试 做 Express Web 测试首先要面对的问题是在哪端进行测试: 客户端的请求响应 ...

  5. Python菜鸟之路:Django 序列化数据

    类型一:对于表单数据进行序列化 这时需要用到ErrorDict. ret['errors'] = obj.errors.as_data() result = json.dumps(ret, cls=J ...

  6. vc判断当前用户是否具有administrator 权限代码

    BOOL IsAdmin() { HANDLE hAccessToken; BYTE * InfoBuffer = ]; PTOKEN_GROUPS ptgGroups; DWORD dwInfoBu ...

  7. django--博客--forms组件-用户注册

    ---------------------------------------------前端页面简易代码----------------------------------------------- ...

  8. 简明python教程七----面向对象的编程(下)

    继承:类之间的类型和子类型关系 代码重用:SchoolMember类被称为 基本类或超类,而Teacher和Student类被称为导出类或者子类 #!/usr/bin/python #Filename ...

  9. 生信笔记-mooc【武大】

    .DNA拓扑学 在拓扑结构的限制下,DNA进行复制等过程.还有连环数=扭转数+缠绕数. 2.拓扑异构酶 DNA变性破坏了两条链之间碱基形成的氢键.和拓扑异构酶是不同的. 3.RNA的组成和结构特点 R ...

  10. appium API java

    原创内容,未经允许,禁止转载! driver.close();//关闭 driver.closeApp();//关闭应用,其实就是按home键把应用置于后台 driver.currentActivit ...