MapReduce-边数据
边数据
边数据(side data)是作业所需的额外的只读数据,以辅助处理主数据集。所面临的挑战在于如何使所有map或reduce任务(这些任务散布在集群内部)都能够方便而高效地使用边数据。
利用Job来配置作业
Configuration类的各种setter方法能够方便地配置作业的任一键值对。如果仅需向任务传递少量元数据则非常有用。用户可以通过Context类的getConfiguration()方法获得配置信息。
一般情况下,基本类型足以应付元数据编码。但对于更复杂的对象,用户要么自己处理序列化工作(这需要实现一个对象与字符串之间的双向转换机制),要么使用Hadoop提供的Stringifier类。DefaultStringifier使用Hadoop的序列化框架来序列化对象。
但是这种机制会加大Hadoop守护进程的内存开销压力,当几百个作业在系统中同时运行时这种现象尤为突出。因此,这种机制并不适合传输多达几千字节的数据量。每次读取配置时,所有项都被读入到内存(即使暂时不用的属性项也不例外)。MR1中,作业配置由jobtracker、tasktracker和子JVM读取,jobtracker和tasktracker均不使用用户的属性,因此这种做法有时既浪费时间,又浪费内存。
代码如下
- package com.zhen.mapreduce.sideData.job;
- import java.io.IOException;
- import org.apache.hadoop.conf.Configuration;
- import org.apache.hadoop.conf.Configured;
- 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.lib.input.FileInputFormat;
- import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
- import org.apache.hadoop.util.Tool;
- import org.apache.hadoop.util.ToolRunner;
- /**
- * @author FengZhen
- * @date 2018年9月23日
- * 边数据(通过job configuration来设置)
- */
- public class SideData extends Configured implements Tool{
- static class SideDataMapper extends Mapper<LongWritable, Text, Text, Text>{
- String sideDataValue = "";
- @Override
- protected void setup(Mapper<LongWritable, Text, Text, Text>.Context context)
- throws IOException, InterruptedException {
- sideDataValue = context.getConfiguration().get("sideData_test_key");
- }
- @Override
- protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, Text>.Context context)
- throws IOException, InterruptedException {
- context.write(value, new Text(sideDataValue));
- }
- }
- public int run(String[] args) throws Exception {
- Configuration configuration = new Configuration();
- configuration.set("sideData_test_key", "sideData_test_value");
- Job job = Job.getInstance(configuration);
- job.setJobName("SideData");
- job.setJarByClass(getClass());
- job.setMapperClass(SideDataMapper.class);
- job.setMapOutputKeyClass(Text.class);
- job.setMapOutputValueClass(Text.class);
- job.setNumReduceTasks(0);
- FileInputFormat.addInputPath(job, new Path(args[0]));
- FileOutputFormat.setOutputPath(job, new Path(args[1]));
- return job.waitForCompletion(true) ? 0 : 1;
- }
- public static void main(String[] args) {
- try {
- String[] params = new String[] {
- "hdfs://fz/user/hdfs/MapReduce/data/sideData/job/input",
- "hdfs://fz/user/hdfs/MapReduce/data/sideData/job/output"
- };
- int exitCode = ToolRunner.run(new SideData(), params);
- System.exit(exitCode);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
分布式缓存
与在作业配置中序列化边数据的技术相比,Hadoop的分布式缓存机制更受青睐,它能够在任务运行过程中及时地将文件和存档复制到任务节点以供使用。为了节约网络带宽,在每一个作业中,各个文件通常只需复制到一个节点一次。
1.用法
对于使用GenericOptionsParser的工具来说,用户可以使用-files选项指定待分发的文件,文件内包含以逗号隔开的URL列表。文件可以存放在本地文件系统、HDFS或其他Hadoop可读文件系统之中(如S3).如果尚未指定文件系统,则这些文件被默认是本地的。即使默认文件系统并非本地文件系统,这也是成立的。
用户可以使用-archives选项向自己的任务中复制存档文件(JAR文件、ZIP文件、tar文件和gzipped tar文件),这些文件会被解档到任务节点。-libjars选项会把JAR文件添加到mapper和reducer任务的类路径中。如果作业JAR文件并非包含很多库JAR文件,这点会很有用。
代码如下
- package com.zhen.mapreduce.sideData.distributedCache;
- import java.io.File;
- import java.io.IOException;
- import org.apache.hadoop.conf.Configured;
- import org.apache.hadoop.fs.Path;
- import org.apache.hadoop.io.IntWritable;
- 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;
- import org.apache.hadoop.util.Tool;
- import org.apache.hadoop.util.ToolRunner;
- import org.apache.log4j.Logger;
- /**
- * @author FengZhen
- * @date 2018年9月23日
- * 读取本地文件边数据
- * 读取不到该文件
- * hadoop jar SideData.jar com.zhen.mapreduce.sideData.distributedCache.MaxTemperatureByStationNameUsingDistributedCacheFile -files /usr/local/test/mr/stations-fixed-width.txt
- */
- public class MaxTemperatureByStationNameUsingDistributedCacheFile extends Configured implements Tool{
- static Logger logger = Logger.getLogger(MaxTemperatureByStationNameUsingDistributedCacheFile.class);
- static enum StationFile{STATION_SIZE};
- static class StationTemperatureMapper extends Mapper<LongWritable, Text, Text, IntWritable>{
- private NcdcRecordParser parser = new NcdcRecordParser();
- @Override
- protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, IntWritable>.Context context)
- throws IOException, InterruptedException {
- parser.parse(value.toString());
- if (parser.isValidTemperature()) {
- context.write(new Text(parser.getStationId()), new IntWritable(parser.getTemperature()));
- }
- }
- }
- static class MaxTemperatureReducerWithStationLookup extends Reducer<Text, IntWritable, Text, IntWritable>{
- private NcdcStationMetadata metadata;
- @Override
- protected void setup(Reducer<Text, IntWritable, Text, IntWritable>.Context context)
- throws IOException, InterruptedException {
- metadata = new NcdcStationMetadata();
- File file = new File("stations-fixed-width.txt");
- metadata.initialize(file);
- context.getCounter(StationFile.STATION_SIZE).setValue(metadata.getStationMap().size());
- }
- @Override
- protected void reduce(Text key, Iterable<IntWritable> values,
- Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
- String stationName = metadata.getStationName(key.toString());
- int maxValue = Integer.MIN_VALUE;
- for (IntWritable value : values) {
- maxValue = Math.max(maxValue, value.get());
- }
- context.write(new Text(stationName), new IntWritable(maxValue));
- }
- }
- public int run(String[] args) throws Exception {
- Job job = Job.getInstance(getConf());
- job.setJobName("MaxTemperatureByStationNameUsingDistributedCacheFile");
- job.setJarByClass(getClass());
- job.setMapperClass(StationTemperatureMapper.class);
- job.setMapOutputKeyClass(Text.class);
- job.setMapOutputValueClass(IntWritable.class);
- job.setReducerClass(MaxTemperatureReducerWithStationLookup.class);
- job.setOutputKeyClass(Text.class);
- job.setOutputValueClass(IntWritable.class);
- FileInputFormat.setInputPaths(job, new Path(args[0]));
- FileOutputFormat.setOutputPath(job, new Path(args[1]));
- return job.waitForCompletion(true) ? 0 : 1;
- }
- public static void main(String[] args) {
- try {
- String[] params = new String[] {
- "hdfs://fz/user/hdfs/MapReduce/data/sideData/distributedCache/input",
- "hdfs://fz/user/hdfs/MapReduce/data/sideData/distributedCache/output"
- };
- int exitCode = ToolRunner.run(new MaxTemperatureByStationNameUsingDistributedCacheFile(), params);
- System.exit(exitCode);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
解析天气数据
- package com.zhen.mapreduce.sideData.distributedCache;
- import java.io.Serializable;
- /**
- * @author FengZhen
- * @date 2018年9月9日
- * 解析天气数据
- */
- public class NcdcRecordParser implements Serializable{
- private static final long serialVersionUID = 1L;
- /**
- * 气象台ID
- */
- private String stationId;
- /**
- * 时间
- */
- private long timeStamp;
- /**
- * 气温
- */
- private Integer temperature;
- /**
- * 解析
- * @param value
- */
- public void parse(String value) {
- String[] values = value.split(",");
- if (values.length >= 3) {
- stationId = values[0];
- timeStamp = Long.parseLong(values[1]);
- temperature = Integer.valueOf(values[2]);
- }
- }
- /**
- * 校验是否合格
- * @return
- */
- public boolean isValidTemperature() {
- return null != temperature;
- }
- public String getStationId() {
- return stationId;
- }
- public void setStationId(String stationId) {
- this.stationId = stationId;
- }
- public long getTimeStamp() {
- return timeStamp;
- }
- public void setTimeStamp(long timeStamp) {
- this.timeStamp = timeStamp;
- }
- public Integer getTemperature() {
- return temperature;
- }
- public void setTemperature(Integer temperature) {
- this.temperature = temperature;
- }
- }
解析气象站数据
- package com.zhen.mapreduce.sideData.distributedCache;
- import java.io.BufferedReader;
- import java.io.File;
- import java.io.FileReader;
- import java.util.HashMap;
- import java.util.Map;
- /**
- * @author FengZhen
- * @date 2018年9月23日
- * 解析边数据
- */
- public class NcdcStationMetadata {
- /**
- * 存放气象站ID和name
- */
- private Map<String, String> stationMap = new HashMap<String, String>();
- public Map<String, String> getStationMap() {
- return stationMap;
- }
- public void setStationMap(Map<String, String> stationMap) {
- this.stationMap = stationMap;
- }
- /**
- * 根据ID获取name
- * @param stationId
- * @return
- */
- public String getStationName(String stationId) {
- return stationMap.get(stationId);
- }
- /**
- * 解析
- * @param value
- */
- public boolean parse(String value) {
- String[] values = value.split(",");
- if (values.length >= 2) {
- String stationId = values[0];
- String stationName = values[1];
- if (null == stationMap) {
- stationMap = new HashMap<String, String>();
- }
- stationMap.put(stationId, stationName);
- return true;
- }
- return false;
- }
- /**
- * 解析气象站数据文件
- * @param file
- */
- public void initialize(File file) {
- BufferedReader reader=null;
- String temp=null;
- try{
- reader=new BufferedReader(new FileReader(file));
- System.out.println("------------------start------------------");
- while((temp=reader.readLine())!=null){
- System.out.println(temp);
- parse(temp);
- }
- System.out.println("------------------end------------------");
- }
- catch(Exception e){
- e.printStackTrace();
- }
- finally{
- if(reader!=null){
- try{
- reader.close();
- }
- catch(Exception e){
- e.printStackTrace();
- }
- }
- }
- }
- }
2.工作机制
当用户启动一个作业,Hadoop会把由-files、-archives和-libjars等选项所指定的文件复制到分布式文件系统(一般是HDFS)之中。接着,在任务运行之前,tasktracker(YARN中NodeManager)将文件从分布式文件系统复制到本地磁盘(缓存)使任务能够访问文件。此时,这些文件就被视为本地化了。从任务的角度看,这些文件就已经在那儿了(它并不关心这些文件是否来自HDFS)。此外,由-libjars指定的文件会在任务启动前添加到任务的类路径(classpath)中。
tasktracker(YARN中NodeManager)为缓存中的文件各维护一个计数器来统计这些文件的被使用情况。当任务即将运行时,该任务所使用的所有文件的对应计数器值增1;当任务执行完毕之后,这些计数器值均减1.当相关计数器值为0时,表明该文件没有被任何任务使用,可以从缓存中移除。缓存的容量是有限的(默认10GB),因此需要经常删除无用的文件以腾出空间来装载新文件。缓存大小可以通过属性local.cache.size进行配置,以字节为单位。
尽管该机制并不确保在同一个tasktracker上运行的同一作业的后续任务肯定能在缓存中找到文件,但是成功的概率相当大。原因在于作业的多个任务在调度之后几乎同时开始运行,因此,不会有足够多的其他作业在运行而导致原始任务的文件从缓存中被删除。
文件存放在tasktracker的${mapred.local.dir}/taskTracker/archive目录下。但是应用程序不必知道这一点,因为这些文件同时以符号链接的方式指向任务的工作目录。
3.分布式缓存API
由于可以通过GenericOptionsParser间接使用分布式缓存,大多数应用不需要使用分布式缓存API。然而,一些应用程序需要用到分布式缓存的更高级的特性,这就需要直接使用API了。API包括两部分:将数据放到缓存中的方法,以及从缓存中读取数据的方法。
- public void addCacheFile(URI uri)
- public void addCacheArchive(URI uri)
- public void setCacheFiles(URI[] files)
- public void setCacheArchives(URI[] archives)
- public void addFileToClassPath(Path file)
- public void addArchiveToClassPath(Path archive)
在缓存中可以存放两类对象:文件(files)和存档(archives)。文件被直接放置在任务节点上,而存档则会被解档之后再将具体文件放置在任务节点上。每种对象类型都包含三种方法:addCacheXXX()、setCacheXXXs()和addXXXToClassPath()。其中,addCacheXXX()方法将文件或存档添加到分布式缓存,setCacheXXXs()方法将一次性向分布式缓存中添加一组文件或存档(之前调用所生成的集合将被替换),addXXXToClassPath()方法将文件或存档添加到MapReduce任务的类路径。
代码如下(有问题,读不到文件)
- package com.zhen.mapreduce.sideData.distributedCache;
- import java.io.File;
- import java.io.FileNotFoundException;
- import java.io.IOException;
- import java.net.URI;
- import org.apache.hadoop.conf.Configured;
- import org.apache.hadoop.fs.Path;
- import org.apache.hadoop.io.IntWritable;
- 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;
- import org.apache.hadoop.util.Tool;
- import org.apache.hadoop.util.ToolRunner;
- import org.apache.log4j.Logger;
- /**
- * @author FengZhen
- * @date 2018年9月23日
- * 读取本地文件边数据
- * 有问题,空指针,读不到文件
- * hadoop jar SideData.jar com.zhen.mapreduce.sideData.distributedCache.MaxTemperatureByStationNameUsingDistributedCacheFileAPI
- */
- public class MaxTemperatureByStationNameUsingDistributedCacheFileAPI extends Configured implements Tool{
- static Logger logger = Logger.getLogger(MaxTemperatureByStationNameUsingDistributedCacheFileAPI.class);
- static enum StationFile{STATION_SIZE};
- static class StationTemperatureMapper extends Mapper<LongWritable, Text, Text, IntWritable>{
- private NcdcRecordParser parser = new NcdcRecordParser();
- @Override
- protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, IntWritable>.Context context)
- throws IOException, InterruptedException {
- parser.parse(value.toString());
- if (parser.isValidTemperature()) {
- context.write(new Text(parser.getStationId()), new IntWritable(parser.getTemperature()));
- }
- }
- }
- static class MaxTemperatureReducerWithStationLookup extends Reducer<Text, IntWritable, Text, IntWritable>{
- private NcdcStationMetadata metadata;
- @Override
- protected void setup(Reducer<Text, IntWritable, Text, IntWritable>.Context context)
- throws IOException, InterruptedException {
- metadata = new NcdcStationMetadata();
- URI[] localPaths = context.getCacheFiles();
- if (localPaths.length == 0) {
- throw new FileNotFoundException("Distributed cache file not found.");
- }
- File file = new File(localPaths[0].getPath().toString());
- metadata.initialize(file);
- context.getCounter(StationFile.STATION_SIZE).setValue(metadata.getStationMap().size());
- }
- @Override
- protected void reduce(Text key, Iterable<IntWritable> values,
- Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
- String stationName = metadata.getStationName(key.toString());
- int maxValue = Integer.MIN_VALUE;
- for (IntWritable value : values) {
- maxValue = Math.max(maxValue, value.get());
- }
- context.write(new Text(stationName), new IntWritable(maxValue));
- }
- }
- public int run(String[] args) throws Exception {
- Job job = Job.getInstance(getConf());
- job.setJobName("MaxTemperatureByStationNameUsingDistributedCacheFileAPI");
- job.setJarByClass(getClass());
- job.setMapperClass(StationTemperatureMapper.class);
- job.setMapOutputKeyClass(Text.class);
- job.setMapOutputValueClass(IntWritable.class);
- job.setReducerClass(MaxTemperatureReducerWithStationLookup.class);
- job.setOutputKeyClass(Text.class);
- job.setOutputValueClass(IntWritable.class);
- job.addCacheFile(new URI("hdfs://fz/user/hdfs/MapReduce/data/sideData/distributedCache/stations-fixed-width.txt"));
- FileInputFormat.setInputPaths(job, new Path(args[0]));
- FileOutputFormat.setOutputPath(job, new Path(args[1]));
- return job.waitForCompletion(true) ? 0 : 1;
- }
- public static void main(String[] args) {
- try {
- String[] params = new String[] {
- "hdfs://fz/user/hdfs/MapReduce/data/sideData/distributedCache/input",
- "hdfs://fz/user/hdfs/MapReduce/data/sideData/distributedCache/output"
- };
- int exitCode = ToolRunner.run(new MaxTemperatureByStationNameUsingDistributedCacheFileAPI(), params);
- System.exit(exitCode);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
MapReduce-边数据的更多相关文章
- MapReduce的数据流程、执行流程
MapReduce的数据流程: 预先加载本地的输入文件 经过MAP处理产生中间结果 经过shuffle程序将相同key的中间结果分发到同一节点上处理 Recude处理产生结果输出 将结果输出保存在hd ...
- Hadoop基础-MapReduce的数据倾斜解决方案
Hadoop基础-MapReduce的数据倾斜解决方案 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.数据倾斜简介 1>.什么是数据倾斜 答:大量数据涌入到某一节点,导致 ...
- mapreduce清洗数据
继上篇 MapReduce清洗数据 package mapreduce; import java.io.IOException; import org.apache.hadoop.conf.Confi ...
- Hadoop第7周练习—MapReduce进行数据查询和实现推简单荐系统
1.1 1.2 :计算员工相关 2.1 内容 :求各个部门的总工资 :求各个部门的人数和平均工资 :求每个部门最早进入公司的员工姓名 :求各个城市的员工的总工资 :列出工资比上司高的员工姓名及其工资 ...
- MapReduce 实现数据join操作
前段时间有一个业务需求,要在外网商品(TOPB2C)信息中加入 联营自营 识别的字段.但存在的一个问题是,商品信息 和 自营联营标示数据是 两份数据:商品信息较大,是存放在hbase中.他们之前唯一的 ...
- MongoDB 的 MapReduce 大数据统计统计挖掘
MongoDB虽然不像我们常用的mysql,sqlserver,oracle等关系型数据库有group by函数那样方便分组,但是MongoDB要实现分组也有3个办法: * Mongodb三种分组方式 ...
- Mapreduce——视频播放数据分类统计
很多视频网站都有电视剧热度排名,一般是依据用户在自己站的行为数据所体现出的受欢迎程度来排名.这里有一份来自优酷.爱奇艺.搜索视频等五大视频网站的一份视频播放数据,我们利用这份数据做些有意义的事情. 金 ...
- MapReduce实例(数据去重)
数据去重: 原理(理解):Mapreduce程序首先应该确认<k3,v3>,根据<k3,v3>确定<k2,v2>,原始数据中出现次数超过一次的数据在输出文件中只出现 ...
- 利用MapReduce实现数据去重
数据去重主要是为了利用并行化的思想对数据进行有意义的筛选. 统计大数据集上的数据种类个数.从网站日志中计算访问地等这些看似庞杂的任务都会涉及数据去重. 示例文件内容: 此处应有示例文件 设计思路 数据 ...
- hadoop mapreduce实现数据去重
实现原理分析: map函数数将输入的文本按照行读取, 并将Key--每一行的内容 输出 value--空. reduce 会自动统计所有的key,我们让reduce输出key-> ...
随机推荐
- Java 基础巩固,根深而叶茂
#J2SE ##基础 八种基本数据类型的大小,以及他们的封装类. 八种基本数据类型,int ,double ,long ,float, short,byte,character,boolean 对应的 ...
- iOS学习笔记(二)——Hello iOS
前面写了iOS开发环境搭建,只简单提了一下安装Xcode,这里再补充一下,点击下载Xcode的dmp文件,稍等片刻会有图一(拖拽Xcode至Applications)的提示,拖拽至Applicatio ...
- 《从零开始学Swift》学习笔记(Day 35)——会使用下标吗?
原创文章,欢迎转载.转载请注明:关东升的博客 看下面的示例代码是不是使用过: var studentList: String[] = ["张三","李四",&q ...
- VS2012如何显示行号
Tools-Options-Text Editor-All Languages –General – Display
- 使用MyBatis_Generator工具jar包自动化生成Dto、Dao、Mapping 文件
由于MyBatis属于一种半自动的ORM框架,所以主要的工作将是书写Mapping映射文件,但是由于手写映射文件很容易出错,所以查资料发现有现成的工具可以自动生成底层模型类.Dao接口类甚至Mappi ...
- SpringBoot-------实现多数据源Demo
之前SpringBoot出来时候就看了下Springboot,感觉的确精简掉了配置文件! 还是很方便的!没办法,我只是个菜鸟! 什么怎么启动Springboot什么的就不说了, 具体的Demo地址我都 ...
- ssm框架整合-过程总结(第三次周总结)
本周主要是完成前端界面和后端的整合. 犹豫前后端的工作完成程度不一致,只实现了部分整合. 登录界面. 可能自己最近没有把重心放在短学期的项目上,导致我们工作的总体进度都要比别慢. 虽然我们只是三个人的 ...
- 小白学linux命令
小白是景女神全栈开发股份有限公司的一名财务实习员工,经过3个月的实习期,小白是过五关斩六将啊!终于成为了公司的一名正式员工,而且收到了景总亲自发来贺喜的邮件:“欢迎你加入大家庭,公司也本着员工全面发展 ...
- Qt for Android 启动短暂的黑屏或白屏问题如何解决?
解决方法一: 使用透明主题 点击项目 -> 在 构建设置 里面找到 Build Android APK 栏目,点击 create templates 创建一个 AndroidManifest.x ...
- GitHub命名规则
● Added ( 新加入的需求 ) ● Fixed ( 修复 bug ) ● Changed ( 完成的任务 ) ● Updated ( 完成的任务,或者由于第三方模块变化而做的变化 )