不多说,直接上代码。

  假如这里有一份邮箱数据文件,我们期望统计邮箱出现次数并按照邮箱的类别,将这些邮箱分别输出到不同文件路径下。

代码版本1

 package zhouls.bigdata.myMapReduce.Email;

 import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.FileSystem;
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.mapreduce.lib.output.MultipleOutputs;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner; //通过MultipleOutputs写到多个文件:参考博客http://www.cnblogs.com/codeOfLife/p/5452902.html // MultipleOutputs 类可以将数据写到多个文件,这些文件的名称源于输出的键和值或者任意字符串。
// 这允许每个 reducer(或者只有 map 作业的 mapper)创建多个文件。 采用name-m-nnnnn 形式的文件名用于 map 输出,name-r-nnnnn 形式的文件名用于 reduce 输出,
// 其中 name 是由程序设定的任意名字, nnnnn 是一个指明块号的整数(从 0 开始)。块号保证从不同块(mapper 或 reducer)输出在相同名字情况下不会冲突。 public class Email extends Configured implements Tool {
public static class MailMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
private final static IntWritable one = new IntWritable(1); @Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
context.write(value, one);
}
} public static class MailReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
private IntWritable result = new IntWritable();
private MultipleOutputs< Text, IntWritable> multipleOutputs; @Override
protected void setup(Context context) throws IOException ,InterruptedException{
multipleOutputs = new MultipleOutputs<Text, IntWritable>(context);
} protected void reduce(Text Key, Iterable<IntWritable> Values,Context context) throws IOException, InterruptedException {
int begin = Key.toString().indexOf("@");//indexOf方法返回一个整数值,指出 String 对象内子字符串的开始位置。
int end = Key.toString().indexOf(".");//indexOf方法返回一个整数值,指出 String 对象内子字符串的开始位置。只不过我们自己写出个end变量而已
// Key.toString().indexOf(ch)
// Key.toString().indexOf(str)
// Key.toString().indexOf(ch, fromIndex)
// Key.toString().indexOf(str, fromIndex)
// Key.toString().intern() // Java中字符串中子串的查找共有四种方法,如下:
// 1、int indexOf(String str) :返回第一次出现的指定子字符串在此字符串中的索引。
// 2、int indexOf(String str, int startIndex):从指定的索引处开始,返回第一次出现的指定子字符串在此字符串中的索引。
// 3、int lastIndexOf(String str) :返回在此字符串中最右边出现的指定子字符串的索引。
// 4、int lastIndexOf(String str, int startIndex) :从指定的索引处开始向后搜索,返回在此字符串中最后一次出现的指定子字符串的索引。 if(begin>=end){
return;
} //获取邮箱类别,比如 qq
String name = Key.toString().substring(begin+1, end);
// String.subString(start,end)截取的字符串包括起点所在的字符串,不包括终点所在的字符串 int sum = 0; for (IntWritable value : Values) {
sum += value.get();
} result.set(sum);
multipleOutputs.write(Key, result, name);
//这里,我们用到的是multipleOutputs.write(Text key, IntWritable value, String baseOutputPath); // multipleOutputs.write默认有3种构造方法:
// multipleOutputs.write(String namedOutput, K key, V value);
// multipleOutputs.write(Text key, IntWritable value, String baseOutputPath);
// multipleOutputs.write(String namedOutput, K key, V value,String baseOutputPath); // MultipleOutputs 类可以将数据写到多个文件,这些文件的名称源于输出的键和值或者任意字符串。
// 这允许每个 reducer(或者只有 map 作业的 mapper)创建多个文件。
// 采用name-m-nnnnn 形式的文件名用于 map 输出,name-r-nnnnn 形式的文件名用于 reduce 输出,
// 其中 name 是由程序设定的任意名字,
// nnnnn 是一个指明块号的整数(从 0 开始)。
// 块号保证从不同块(mapper 或 reducer)写的输出在相同名字情况下不会冲突。 } @Override
protected void cleanup(Context context) throws IOException ,InterruptedException{
multipleOutputs.close();
} } public int run(String[] args) throws Exception {
Configuration conf = new Configuration();// 读取配置文件 Path mypath = new Path(args[1]);
FileSystem hdfs = mypath.getFileSystem(conf);//创建输出路径
if (hdfs.isDirectory(mypath)) {
hdfs.delete(mypath, true);
}
Job job = Job.getInstance();// 新建一个任务
job.setJarByClass(Email.class);// 主类 FileInputFormat.addInputPath(job, new Path(args[0]));// 输入路径
FileOutputFormat.setOutputPath(job, new Path(args[1]));// 输出路径 job.setMapperClass(MailMapper.class);// Mapper
job.setReducerClass(MailReducer.class);// Reducer job.setOutputKeyClass(Text.class);// key输出类型
job.setOutputValueClass(IntWritable.class);// value输出类型 job.waitForCompletion(true);
return 0;
} public static void main(String[] args) throws Exception {
String[] args0 = {
"hdfs://HadoopMaster:9000/inputData/multipleOutputFormats/mail.txt",
"hdfs://HadoopMaster:9000/outData/MultipleOutputFormats/" };
int ec = ToolRunner.run(new Configuration(), new Email(), args0);
System.exit(ec);
}
}

代码版本1

 package zhouls.bigdata.myMapReduce.Email;

 import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.FileSystem;
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.mapreduce.lib.output.MultipleOutputs;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner; //假如这里有一份邮箱数据文件,我们期望统计邮箱出现次数并按照邮箱的类别,将这些邮箱分别输出到不同文件路径下。
/*wolys@21cn.com
zss1984@126.com
294522652@qq.com
simulateboy@163.com
zhoushigang_123@163.com
sirenxing424@126.com
lixinyu23@qq.com
chenlei1201@gmail.com
370433835@qq.com
cxx0409@126.com
viv093@sina.com
q62148830@163.com
65993266@qq.com
summeredison@sohu.com
zhangbao-autumn@163.com
diduo_007@yahoo.com.cn
fxh852@163.com /out/163-r-00000
/out/126-r-00000
/out/21cn-r-00000
/out/gmail-r-00000
/out/qq-r-00000
/out/sina-r-00000
/out/sohu-r-00000
/out/yahoo-r-00000
/out/part-r-00000
*/ public class Email extends Configured implements Tool{
public static class MailMapper extends Mapper<LongWritable, Text, Text, IntWritable>{
private final static IntWritable one = new IntWritable(1);//赋值1给one @Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
context.write(value, one);//将value和one写入到context里。 value是k2,one是v2
// context.write(new Text(value),new IntWritable(one));等价
// key默认是行偏移量,可以自己自定义改 }
} // MultipleOutputs将结果输出到多个文件或文件夹的步骤:
// 见博客http://tydldd.iteye.com/blog/2053867 public static class MailReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
private IntWritable result = new IntWritable();
private MultipleOutputs<Text, IntWritable> multipleOutputs;//MultipleOutputs将结果输出到多个文件或文件夹
// 因为,MultipleOutputs是将结果输出到多个文件或文件夹,那么结果是什么,则就是k3,v3啦。即在这里就是MultipleOutputs<Text, IntWritable> multipleOutputs; //创建对象,以下是模板,别怕
protected void setup(Context context) throws IOException ,InterruptedException{
multipleOutputs = new MultipleOutputs<Text, IntWritable>(context);
} protected void reduce(Text Key, Iterable<IntWritable> Values,Context context) throws IOException, InterruptedException{
//294522652@qq.com
int begin = Key.toString().indexOf("@");//indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。 即begin是9
int end = Key.toString().indexOf(".");//indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。 即end是12
if(begin>=end){
return;
} //获取邮箱类别,比如 qq
String name = Key.toString().substring(begin+1, end);//substring()是去除指定字符串的方法,及substring(10,12)
int sum = 0;
for (IntWritable value : Values) {//计数,for星型循环,即将Iterable<IntWritable> Values的值,一一传给IntWritable value
sum += value.get();//就是拿取IntWritable类型的value的值,给value类型的sum
}
result.set(sum);//即求和计数,如wolys@21cn.com出现了几次几次。
multipleOutputs.write(Key, result, name);//将Key和result和name一起写入multipleOutputs /*
* http://www.cnblogs.com/codeOfLife/p/5452902.html
* multipleOutputs.write(key, value, baseOutputPath)方法的第三个函数表明了该输出所在的目录(相对于用户指定的输出目录)。
* 如果baseOutputPath不包含文件分隔符"/",那么输出的文件格式为baseOutputPath-r-nnnnn(name-r-nnnnn);
* 如果包含文件分隔符"/",例如baseOutputPath="029070-99999/1901/part",那么输出文件则为029070-99999/1901/part-r-nnnnn
*/
} //关闭对象,以下是模板,别怕
protected void cleanup(Context context) throws IOException ,InterruptedException{
multipleOutputs.close();
}
} public int run(String[] arg0) throws Exception{
Configuration conf = new Configuration();// 读取配置文件
Path mypath = new Path(arg0[1]);//下标为1,即是输出路径
FileSystem hdfs = mypath.getFileSystem(conf);//FileSystem对象hdfs
if (hdfs.isDirectory(mypath))
{
hdfs.delete(mypath, true);
}
Job job = Job.getInstance();// 新建一个任务
job.setJarByClass(Email.class);// 主类 job.setMapperClass(MailMapper.class);// Mapper
job.setReducerClass(MailReducer.class);// Reducer job.setOutputKeyClass(Text.class);// key输出类型
job.setOutputValueClass(IntWritable.class);// value输出类型 FileInputFormat.addInputPath(job, new Path(arg0[0]));// 文件输入路径
FileOutputFormat.setOutputPath(job, new Path(arg0[1]));// 文件输出路径
job.waitForCompletion(true); return 0;
} public static void main(String[] args) throws Exception{
//集群路径
// String[] args0 = { "hdfs://HadoopMaster:9000/email/email.txt",
// "hdfs://HadoopMaster:9000/out/email"}; //本地路径
String[] args0 = { "./data/email/email.txt",
"out/email/"}; int ec = ToolRunner.run( new Configuration(), new Email(), args0);
System. exit(ec);
}
}

Hadoop MapReduce编程 API入门系列之MapReduce多种输出格式分析(十九)的更多相关文章

  1. Hadoop MapReduce编程 API入门系列之MapReduce多种输入格式(十七)

    不多说,直接上代码. 代码 package zhouls.bigdata.myMapReduce.ScoreCount; import java.io.DataInput; import java.i ...

  2. Hadoop MapReduce编程 API入门系列之自定义多种输入格式数据类型和排序多种输出格式(十一)

    推荐 MapReduce分析明星微博数据 http://git.oschina.net/ljc520313/codeexample/tree/master/bigdata/hadoop/mapredu ...

  3. Hadoop MapReduce编程 API入门系列之Crime数据分析(二十五)(未完)

    不多说,直接上代码. 一共12列,我们只需提取有用的列:第二列(犯罪类型).第四列(一周的哪一天).第五列(具体时间)和第七列(犯罪场所). 思路分析 基于项目的需求,我们通过以下几步完成: 1.首先 ...

  4. Hadoop MapReduce编程 API入门系列之网页排序(二十八)

    不多说,直接上代码. Map output bytes=247 Map output materialized bytes=275 Input split bytes=139 Combine inpu ...

  5. Hadoop MapReduce编程 API入门系列之二次排序(十六)

    不多说,直接上代码. -- ::, INFO [org.apache.hadoop.metrics.jvm.JvmMetrics] - Initializing JVM Metrics with pr ...

  6. Hadoop MapReduce编程 API入门系列之分区和合并(十四)

    不多说,直接上代码. 代码 package zhouls.bigdata.myMapReduce.Star; import java.io.IOException; import org.apache ...

  7. Hadoop MapReduce编程 API入门系列之压缩和计数器(三十)

    不多说,直接上代码. Hadoop MapReduce编程 API入门系列之小文件合并(二十九) 生成的结果,作为输入源. 代码 package zhouls.bigdata.myMapReduce. ...

  8. Hadoop MapReduce编程 API入门系列之挖掘气象数据版本3(九)

    不多说,直接上干货! 下面,是版本1. Hadoop MapReduce编程 API入门系列之挖掘气象数据版本1(一) 下面是版本2. Hadoop MapReduce编程 API入门系列之挖掘气象数 ...

  9. Hadoop MapReduce编程 API入门系列之挖掘气象数据版本2(十)

    下面,是版本1. Hadoop MapReduce编程 API入门系列之挖掘气象数据版本1(一) 这篇博文,包括了,实际生产开发非常重要的,单元测试和调试代码.这里不多赘述,直接送上代码. MRUni ...

随机推荐

  1. Vs2010删除空白行

    在copy了别人的代码之后,出现了大量的空白行,批量删除空白行方法为: 查找内容:^:b*$\n 替换为: 查找范围:当前文档 使用:正则表达式

  2. [Advanced Algorithm] - Inventory Update

    题目 依照一个存着新进货物的二维数组,更新存着现有库存(在 arr1 中)的二维数组. 如果货物已存在则更新数量 . 如果没有对应货物则把其加入到数组中,更新最新的数量. 返回当前的库存数组,且按货物 ...

  3. 身份认证防止重放攻击的challenge-response方法

    或者叫询问-应答机制. 基于挑战/应答(Challenge/Response)方式的身份认证系统就是每次认证时认证服务器端都给客户端发送一个不同的"挑战"字串,客户端程序收到这个& ...

  4. react新版本生命周期

    给componentWillMount componentWillReceiveProps componentWillUpdate生命周期加上UNSAFE_前缀,表明其不安全性,并将在未来版本将其移除 ...

  5. PAT_A1098#Insertion or Heap Sort

    Source: PAT_A1098 Insertion or Heap Sort (25 分) Description: According to Wikipedia: Insertion sort  ...

  6. 操作符重载、继承(day08)

    二十 操作符重载 函数操作符"()" 功能:让对象当做函数来使用 注:对参数的个数.返回类型没有限制 eg: class A{...}; A a; //a.operator()(1 ...

  7. 51nod1596 搬货物

    现在有n个货物,第i个货物的重量是 2wi .每次搬的时候要求货物重量的总和是一个2的幂.问最少要搬几次能把所有的货物搬完. 样例解释: 1,1,2作为一组. 3,3作为一组. Input 单组测试数 ...

  8. php实现网站访客数量统计的方法(简单实现,不能防刷新)

    方法一: <?php function Counter()//定义函数 { $five = "00000";//声明变量,$five,$four等变量表示零的个数,放在数字前 ...

  9. python笔记之json报错

    写爬虫的过程中不免遇到处理json数据的情况,今天在爬取新华网新闻数据时发现使用json.loads函数时报错: json.decoder.JSONDecodeError: Expecting val ...

  10. tp5 封装百度地图api接口

    //服务器端api extend\Map <?php /** * 百度地图业务封装 */ class Map{ /** * 根据地址来获取经纬度 * @param $address */ pub ...