MapReduce处理两个文件内不同行信息

文章目录

    • MapReduce处理两个文件内不同行信息
  • 一、MapRedce简单介绍
  • 二、题目要求
  • 三、详细步骤
    • 1.创建项目(高端玩家请跳过)
    • 2.分析题目
    • 3.开始干活吧

# 前言

提示:内容仅供参考学习,直接拿来交作业大家一起陪zyf老师喝茶

一、MapRedce简单介绍

MapReduce的背景和基本概念网上特别多,感兴趣可以直接去百度。
在我看来这玩意就是,你可爱的zyf老师给你了一个大任务,你一个人需要很长很长很长时间才能完成,但他给的时间又非常少,你为了加快效率就把这个大任务分成了很多个小任务给你可爱的室友,多个室友同时进行多个小任务以加快效率,但问题来了,在java中这个过程是很复杂的,你需要面临很多问题,比如大任务分成多少个小任务,小任务都分给了谁,每个室友完成任务之后结果如何汇总,万一某个室友去保卫提瓦提大陆忘记了你分的任务怎么办?不过幸运的是开发人员给我们解决了这个问题,解决方法就是MapReduce框架

二、题目要求

编程题2:找出两个文件的不同行
已知有两个文件people1.txt和people2.txt,两个文件中均为用户的信息,包含用户的姓名,身份证号,家庭住址,联系方式。请使用MapReduce程序找出两个文件数据中不同的行。
不同的行的判断标准:

  1. 用户A的信息只在其中一个文件中,则需要输出用户信息及所在文件名。
  2. 用户A的信息在两个文件中均存在,但是身份证号相同,而姓名、家庭住址和联系方式三个字段中至少有一个不同,则需要同时分别输出两个文件中的用户A信息
    输出格式为:
    用户信息 文件1-存在,文件名2-不存在
    文件1:用户信息;文件2:用户信息 内容不同

三、详细步骤

1.创建项目(高端玩家请跳过)

示例如下(IDEA版本为2019.3.2,Hadoop版本为3.2.2):



 <!--自定义的一些属性:一般都用来定义依赖的版本--><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><hadoop.version>3.2.2</hadoop.version><hive.version>3.1.2</hive.version><hbase.version>2.3.4</hbase.version><junit.version>4.13.2</junit.version><slf4j.version>1.7.30</slf4j.version></properties><dependencies><!--Hadoop依赖--><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-client</artifactId><version>3.2.2</version></dependency><!--单元测试依赖--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><!--日志框架依赖--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>${slf4j.version}</version></dependency><dependency><groupId>org.testng</groupId><artifactId>testng</artifactId><version>RELEASE</version><scope>compile</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>compile</scope></dependency></dependencies>

2.分析题目

根据题目要求,我们需要从两个文本文件中读取信息,然后进行对比,找出信息不同或单独出现的行,我们需要解决两个问题
1.从两个文件中获取信息,因为题目要求,我们还需要识别出信息的来源,即从那个文件中获取的信息,这段操作在主要Mapper里。
2.处理获取的信息,也就是编写业务逻辑,这里就是处理字符串,都写在Reduce里了

3.开始干活吧

明白了所需要的解决的问题就可以开始干活了
完整代码和源数据在最后,你可以先复制到你的项目里,方便查看和实验,但不要拿它交作业,会出人命的。

1.首先为了存放信息方便,我们需要创建一个实体类People,具体信息看最下面代码,需要注意的是这个实体类和平时创建的实体类有所不同,需要实现一个WritableComparable接口,重写write和readFields方法。
2.Mapper环节
编写Mapper方法,使LSMapper继承Mapper,关于Mapper中的四个值的意义,在后面代码的注释中有写,可以自行阅读

通过在Mapper中添加控制台输出你会发现,Mapper一次会读取一行数据,把读取到的这行数据传递给value,我们通过空格进行分割字符串就可以得到我们需要的信息,把这些信息封装成一个对象通过context.write()传给Reduce,Mapper的工作就完成了,
3.Reduce环节
使LSReduce继承Reduce,参数问题参考Mapper注释。现在我们已经知道,我们所需要的信息已经被Mapper从文件中读出并且一个一个的传到Reduce这里,但是我们怎么获取呢?这时我们就需要知道Reduce拿到了一堆什么类型,什么格式的值。
通过在这两个位置进行输出
以及对结果的分析,我们知道了


1.Reduce只执行一次
2.得到的值被封装成了一个类似数组的东西values,我们可以通过遍历得到每一个对象值

得到了值之后我们要对值进行分家,来自people1.txt的放到peo1,来自people2.txt的放到peo2,剩下的工作就是编写业务逻辑,逻辑很简单,代码里有注释,相信你们看的懂
4.Runner环节
最后我们要为Mapper和Reduce写一个启动类,里面需要配置很多东西,在代码里都有详细注释,这里不多赘述。

People

package entiy;import org.apache.hadoop.io.WritableComparable;import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;public class People implements WritableComparable<People> {private String name;private String id;private String address;private String call;private String fileName;public void set(String name, String id, String address, String call, String fileName) {this.name = name;this.id = id;this.address = address;this.call = call;this.fileName = fileName;}public People() {}public People(String name, String id, String address, String call, String fileName) {this.name = name;this.id = id;this.address = address;this.call = call;this.fileName = fileName;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public String getCall() {return call;}public void setCall(String call) {this.call = call;}public String getFileName() {return fileName;}public void setFileName(String fileName) {this.fileName = fileName;}@Overridepublic int compareTo(People o) {return 0;}@Overridepublic void write(DataOutput dataOutput) throws IOException {dataOutput.writeUTF(name);dataOutput.writeUTF(id);dataOutput.writeUTF(address);dataOutput.writeUTF(call);dataOutput.writeUTF(fileName);}@Overridepublic void readFields(DataInput dataInput) throws IOException {name = dataInput.readUTF();id = dataInput.readUTF();address = dataInput.readUTF();call = dataInput.readUTF();fileName = dataInput.readUTF();}@Overridepublic String toString() {return "People{" +"name='" + name + '\'' +", id='" + id + '\'' +", address='" + address + '\'' +", call='" + call + '\'' +", fileName='" + fileName + '\'' +'}';}}

LSMapper

package mapper;import entiy.People;
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.mapreduce.lib.input.FileSplit;import java.io.IOException;/*Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT>它的这个Mapper让你去定义四个泛型,Reduce也一样* 4个泛型,前两个是指定mapper端输入数据的类型* 拿数据,输出数据都是以<key,value>的形式进行的--那么key,value都分别有一个数据类型* KEYIN:输入的key的类型 ,在mapper里面这个变量指的是偏移量,意思就是从第几个字节开始读,开始是0,读取一行之后,如果一行有50个字节,偏移量就会变成52(换行符虽然看不见但是也占用2个字节),汉字占3个,空格数字都是占一个* VALUEIN:输入的value的类型,通常是Text(即String的序列化值)* KEYOUT:输出的key的数据类型* VALUEOUT:输出的value的数据类型*/
public class LSMapper extends Mapper<LongWritable, Text, IntWritable,People > {String fileName;@Overrideprotected void setup(Context context) throws IOException, InterruptedException {FileSplit fileSplit = (FileSplit)context.getInputSplit();//获取文件切片对象fileName = fileSplit.getPath().getName();//获取文件名}@Overrideprotected void map(LongWritable key, Text value, Context context)throws IOException, InterruptedException {People people = new People();String line = value.toString();//切分单词,这个是按照特定的分隔符 进行切分String [] words = line.split(" ");//给对象赋值people.setName(words[0]);people.setId(words[1]);people.setAddress(words[2]);people.setCall(words[3]);people.setFileName(fileName);System.out.println("偏移量:"+key);System.out.println("对象值:"+people);//将赋好值的对象通过context.write()传递给Reducecontext.write(new IntWritable(1),people);}
}

LSReduce

package reduce;import entiy.People;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
import java.util.ArrayList;//测试输出我注释了
/*
* 这里Reduer的四个变量分别指
* IntWritable:Reduce得到的key类型
* People:Reduce得到的value类型
* Text:Reduce将要输出的key类型
*  Text:Reduce将要输出的value类型
* */
public class LSReducer extends Reducer<IntWritable,People , Text,Text> {private ArrayList<People> peo1 = new ArrayList<>();//用于存放people1.txt的数据private ArrayList<People> peo2 = new ArrayList<>();//用于存放people2.txt的数据@Overrideprotected void reduce(IntWritable key, Iterable<People> values, Context context)throws IOException, InterruptedException {//  System.out.println("快乐输出");for (People value : values) {     //通过foreath遍历values的值// System.out.println(key);// System.out.println(value);People newValue =new People();newValue.set(value.getName(),value.getId(),value.getAddress(),value.getCall(),value.getFileName());//将得到的值赋值给一个新建对象newValueif(newValue.getFileName().equals("people1.txt")){     //判断数据源peo1.add(newValue);}else {peo2.add(newValue);}}for (People people1:peo1) {int k=0;for (People people2:peo2) {if(people1.getName().equals(people2.getName())&&people1.getId().equals(people2.getId())){//姓名,id相同情况判断后续信息if(!people1.getAddress().equals(people2.getAddress())||!people1.getCall().equals(people2.getCall())){String string1 = "信息不同"+" "+"\n"+ "文件1:"+people1.getName()+" "+people1.getId()+" "+people1.getAddress()+" "+people1.getCall()+"\n"+"文件2:"+people2.getName()+" "+people2.getId()+" "+people2.getAddress()+" "+people2.getCall();context.write(new Text(string1),new Text());}k=1;}}//如果执行到这里k=0说明people1没有相同的信息,他是个孤儿if(k==0){String string2 = people1.getName()+" "+people1.getId()+" "+people1.getAddress()+" "+people1.getCall()+" 文件1存在"+" "+"文件2不存在";context.write(new Text(string2),new Text());}}//下面这个类似for (People people2:peo2) {int k=0;for (People people1:peo1) {if(people2.getName().equals(people1.getName())&&people2.getId().equals(people1.getId())){//姓名,id相同情况判断后续信息k=1;}}if(k==0){String string2 = people2.getName()+" "+people2.getId()+" "+people2.getAddress()+" "+people2.getCall()+" 文件2存在"+" "+"文件1不存在";context.write(new Text(string2),new Text());}}}
}

Runner

package run;
import entiy.People;
import mapper.LSMapper;
import org.apache.commons.io.FileUtils;
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 reduce.LSReducer;import java.io.File;
import java.io.IOException;public class Runner {public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {//创建一个job用来执行任务,老工具人了Job job = Job.getInstance(new Configuration());//job用哪个类作为Mapper 指定输入输出数据类型是什么job.setMapperClass(LSMapper.class);job.setMapOutputKeyClass(IntWritable.class);job.setMapOutputValueClass(People.class);//job用哪个类作为Reducer 指定数据输入输出类型是什么job.setReducerClass(LSReducer.class);job.setOutputKeyClass(Text.class);job.setOutputValueClass(Text.class);Path pathIn1 = new Path("写你自己的路径吧");//输入文件(也就是源数据文件)目录1Path pathIn2 = new Path("写你自己的路径吧");//输入文件目录2Path pathOut1 = new Path("写你自己的路径吧");//输出文件目录FileInputFormat.setInputPaths(job, pathIn1,pathIn2);//创建文件输入流,读取源文件File file = new File(String.valueOf(pathOut1));if(file.exists()){FileUtils.deleteDirectory(file);//这里做了一个简单地判断,输出文件目录存在,自动删除,妈妈再也不用担心文件已存在报错了}FileOutputFormat.setOutputPath(job, pathOut1);//输出目标文件//提交int isok =  job.waitForCompletion(true)?0:-1;System.exit(isok);}
}

源文件数据people1.txt

奥特曼 201919123321 日本东京 62323123188
赛亚人 201919454353 日本东京 21321343345
绘梨衣 201919213232 日本东京 17546034485
路明非 201919244125 中国上海 14686544105
楚子航 201919244102 中国上海 19537485216
陈墨瞳 201919244456 中国杭州 17843950129
绿巨人 201919244667 美国纽约 45678613466

源文件数据people2.txt

奥特曼 201919123321 日本东京 62323123188
赛亚人 201919454353 日本东京 21321343345
绘梨衣 201919213232 日本东京 17546023132
路明非 201919244125 中国香港 14686544105
楚子航 201919244102 中国上海 19537485216
陈墨瞳 201919244456 中国杭州 17843950129
钢铁侠 202019244789 美国纽约 99656455637

输出结果

绿巨人 201919244667 美国纽约 45678613466 文件1存在 文件2不存在
信息不同
文件1:路明非 201919244125 中国上海 14686544105
文件2:路明非 201919244125 中国香港 14686544105
信息不同
文件1:绘梨衣 201919213232 日本东京 17546034485
文件2:绘梨衣 201919213232 日本东京 17546023132
钢铁侠 202019244789 美国纽约 99656455637 文件2存在 文件1不存在  

MapReduce处理两个文件内不同行信息相关推荐

  1. python统计行号_用Python实现两个文件的不同行的编号

    title: 文件不同行 tags: python,IO,dict 比较两个文件在哪些行内容不同,返回这些行的编号,行号编号从1开始. 定义统计文件行数的函数 # 统计文件个数def statLine ...

  2. PHP有限内存处理大文件(从两个文件提取相同行)

    面试题: 有两个文件文件,大小都超过了1G,一行一条数据,每行数据不超过500字节,两文件中有一部分内容是完全相同的,请写代码找到相同的行,并写到新文件中.PHP最大允许内内为256M. 解题步骤 遇 ...

  3. python读取google earth导出的kml文件内的经纬度信息

     首先利用google earth,描出河段中心线,并导出kml文件  提取kml内的经纬度信息 import kml2geojson as k2g import geopandas as gpd i ...

  4. 利用Python提取PDF文件中的文本信息

    如何利用Python提取PDF文件中的文本信息 日常工作中我们经常会用到pdf格式的文件,大多数情况下是浏览或者编辑pdf信息,但有时候需要提取pdf中的文本,如果是单个文件的话还可以通过复制粘贴来直 ...

  5. c语言学生信息结构体录入文件,C语言—学生信息管理系统

    学习了C语言结构体,链表和文件的知识之后,就可以做出一个学生信息管理系统了,下面的是我在刚学习完这块知识后写出来的,基本没什么界面,不过 能够实现  录入,添加,插入,遍历,删除,查询,并且保存到本地 ...

  6. 威纶通触摸屏分期付款锁机(带PC程序) 文件内包含 威纶通触摸屏源程序例子(含宏程序) 总共两个页面可以快速移植到自己的程序上

    威纶通触摸屏分期付款锁机(带PC程序) 文件内包含 威纶通触摸屏源程序例子(含宏程序) 总共两个页面可以快速移植到自己的程序上. 带PC端程序自动计算设定时间密码. 宏程序带详细注释,适合学习 可以动 ...

  7. 找出两个文件内容的相同与不同

    此文略有自己改动(DOOM) 1  comm命令 在我们的开发和运营中,特别是对业务进行监控的时候,我们常常需要写一些监控shell脚本,而这些脚本需要求两个文件的共同的记录列表或者只出现在第一个文件 ...

  8. 通过python利用哈希值实现比较两个文件的一致性

    背景 近来学习到python的内置函数hash(),深入发现通过python的哈希值可以做很多的事情,最典型的可能就是文件加密了,在我们现实生活中大约有如下一些用途: 加密网站注册用户的密码. 网站用 ...

  9. 设计所需的各种输出格式(包括整数、实数、字符串等),用一个文件名format.h把这些信息都包括到此文件内,另编写一个文件,用文件包含命令验证可以使用这些格式

    <程序设计基础-c语言>杨莉 刘鸿翔 ISBN-978-7-03-032903-5 p241 习题7 16.设计所需的各种输出格式(包括整数.实数.字符串等),用一个文件名"fo ...

最新文章

  1. Windows四大傻X功能——那些拖慢系统性能的罪魁祸首
  2. java+testng接口测试入门
  3. java jpanel 间距_Java的 . 调整JPanel上的问题大小
  4. linux shell之得到当前路径下的目录
  5. UE3 性能、分析及优化
  6. 火狐firefox插件配合scrapy,注意tbody会导致empty
  7. VB连接Mysql数据库
  8. Cadence Allegro 高亮功能的使用技巧图文教程
  9. 利用四阶龙格库塔法(Runge-Kutta methods)求解常微分方程并用其迭代式用MATLAB绘制分叉混沌图
  10. Java 简单工厂模式
  11. R语言计算dataframe中指定数据列的值为缺失值的样本个数(行的个数)
  12. Opencv打开basler相机——实现显示视频、保存图片、记录视频(Windows下)
  13. JavaScript屏蔽Backspace键
  14. 534 Policy requires SSL错误
  15. 今天sql练习遇到的问题
  16. 一款非常实用的视频剪辑软件,它可以满足您进行视频制作的需要
  17. C语言printf()左对齐和右对齐
  18. 15051:小Biu的区间和
  19. 30行Python代码,抓取全网实时热点,获取最新资讯
  20. MySQL数据库(九) 集群 Cluster 和性能优化

热门文章

  1. JS异步:执行原理与回调
  2. 【Python进阶】9- Pandas的应用
  3. Android模仿微信语音聊天功能
  4. 如何搭建自己的内测分发平台?有可以直接用的内测分发平台吗?
  5. 京训钉怎么快速看完_在钉钉用培训机构CRM管理系统,助力协同办公一体化
  6. 加快打造“云上贵州”,靠大数据实现“后发赶超”
  7. 【微信小程序】实现简单轮播图效果
  8. 头歌 MongoDB 文档的高级查询操作(全部关卡)
  9. 四大行、城商行等银行都在使用什么数据库?
  10. Efficientnet笔记:各个框架最适合的图像尺寸