边数据

边数据(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-边数据的更多相关文章

  1. MapReduce的数据流程、执行流程

    MapReduce的数据流程: 预先加载本地的输入文件 经过MAP处理产生中间结果 经过shuffle程序将相同key的中间结果分发到同一节点上处理 Recude处理产生结果输出 将结果输出保存在hd ...

  2. Hadoop基础-MapReduce的数据倾斜解决方案

    Hadoop基础-MapReduce的数据倾斜解决方案 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.数据倾斜简介 1>.什么是数据倾斜 答:大量数据涌入到某一节点,导致 ...

  3. mapreduce清洗数据

    继上篇 MapReduce清洗数据 package mapreduce; import java.io.IOException; import org.apache.hadoop.conf.Confi ...

  4. Hadoop第7周练习—MapReduce进行数据查询和实现推简单荐系统

    1.1 1.2 :计算员工相关 2.1 内容 :求各个部门的总工资 :求各个部门的人数和平均工资 :求每个部门最早进入公司的员工姓名 :求各个城市的员工的总工资 :列出工资比上司高的员工姓名及其工资 ...

  5. MapReduce 实现数据join操作

    前段时间有一个业务需求,要在外网商品(TOPB2C)信息中加入 联营自营 识别的字段.但存在的一个问题是,商品信息 和 自营联营标示数据是 两份数据:商品信息较大,是存放在hbase中.他们之前唯一的 ...

  6. MongoDB 的 MapReduce 大数据统计统计挖掘

    MongoDB虽然不像我们常用的mysql,sqlserver,oracle等关系型数据库有group by函数那样方便分组,但是MongoDB要实现分组也有3个办法: * Mongodb三种分组方式 ...

  7. Mapreduce——视频播放数据分类统计

    很多视频网站都有电视剧热度排名,一般是依据用户在自己站的行为数据所体现出的受欢迎程度来排名.这里有一份来自优酷.爱奇艺.搜索视频等五大视频网站的一份视频播放数据,我们利用这份数据做些有意义的事情. 金 ...

  8. MapReduce实例(数据去重)

    数据去重: 原理(理解):Mapreduce程序首先应该确认<k3,v3>,根据<k3,v3>确定<k2,v2>,原始数据中出现次数超过一次的数据在输出文件中只出现 ...

  9. 利用MapReduce实现数据去重

    数据去重主要是为了利用并行化的思想对数据进行有意义的筛选. 统计大数据集上的数据种类个数.从网站日志中计算访问地等这些看似庞杂的任务都会涉及数据去重. 示例文件内容: 此处应有示例文件 设计思路 数据 ...

  10. hadoop mapreduce实现数据去重

    实现原理分析: map函数数将输入的文本按照行读取,   并将Key--每一行的内容   输出    value--空. reduce  会自动统计所有的key,我们让reduce输出key-> ...

随机推荐

  1. VS2008试用版到期解决办法----win7下VS2008升级补丁.zip

    打开好久没用的Visual studio 2008,才知道试用版已经到期了.在网上找来了序列号,可是连一个输入序列号的地方都没有,困惑了好久,终于找到了解决办法. 首先献上自己收集的Visual st ...

  2. 学生成绩管理系统【c】

    #include<stdio.h> #include<stdlib.h> #include<string.h> #include<conio.h> #d ...

  3. css,查询相应标签,div等

    1.类名 .类别 例子: 查询类名为“useradd” .useradd{ margin-top:50px; margin-left:200px;} 2.属性找 例子:查询类为useradd下的inp ...

  4. 双向认证 HTTPS双向认证

    [微信支付]微信小程序支付开发者文档 https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=4_3 HTTPS双向认证使用说明 ...

  5. 是面向对象设计五个基本原则(SOLID)

    单一职责原则 - 搜狗百科 https://baike.sogou.com/v51360965.htm 单一职责原则并不是一个孤立的面向对象设计原则,它是面向对象设计五个基本原则(SOLID)之一.这 ...

  6. 【python】-- Django 分页 、cookie、Session、CSRF

    Django  分页 .cookie.Session.CSRF 一.分页 分页功能在每个网站都是必要的,下面主要介绍两种分页方式: 1.Django内置分页 from django.shortcuts ...

  7. 洛谷 P1407 [国家集训队]稳定婚姻

    洛谷 这个题面很有意思,像我这样的菜鸡,完全不需考虑婚姻的稳定 性 问题. tarjan裸题,直接讲算法吧: 原配夫妻之间分别连一条边,小情人之间反向连边. 这时候我们会发现一个性质,如果婚姻稳定,那 ...

  8. 读取用户家目录下的配置文件到properties

    String conf = System.getProperty("user.home") + File.separator + "a.properties"; ...

  9. locust参数化

    前面用篇专门讲了requests实现接口的参数关联案例,这里直接转化成locust脚本就行了 # coding:utf-8 from locust import HttpLocust, TaskSet ...

  10. 001infor record 计划时间取值增强-20150622

    ZMD_MRP_PARAMETERS 3000公司下工厂跑MRP时,如果为外购则通过外挂表取infor record计划交期. METHOD if_ex_md_mrp_parameters~adjus ...