Hadoop_day07学习笔记

一、零散知识

1.序列化:把结构化对象转化为字节流

2.反序列化  序列化的逆过程 把字节流转化为结构化对象

3.序列化格式特点:紧凑:高效使用存储空间。
                            快速:读写数据的额外开销小
                            可扩展:可透明地读取老格式的数据

                            互操作:支持多语言的交互

hadoop的序列化格式 : Writable

4.序列化在分布式环境的两大作用:进程间通信,永久存储。

即节点一  传输文件至节点二 1上消息序列化为二进制流   中间二进制流传输   2上二进制流反序列化为消息

5.很重要

Writable接口, 
是根据 DataInput 和 DataOutput 实现的简单、有效的序列化对象.

MR的任意Key和Value必须实现Writable接口.

MR的任意key必须实现WritableComparable接口

6.hadoop中的数据类型

Hadoop_day07学习笔记_第1张图片

1~5这种类似于数据库中的varchar()有多少占多少弹性的

二、案例

概述、hadoop最多可以提供两对输入输出的key value对 超出的话该怎么办

所以引入了自定义Writable类  (前面讲过所有的key value都要去实现Writable接口)

package com.myreduce;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

import org.apache.hadoop.io.Writable;

/**
 * 这是自己定义的一个Writable类
 * 因为hadoop只能提供两个的输入输出的数据操作  而我们要处理四个的超出了负载 所以需要自己定义一个 MapReduce任意的key
 * value都实现了Writable接口(可以查看源码) MapReduce任意的key 都必须实现Writablecomparable
 * 
 * @author zzh
 *
 */
public class Traffic implements Writable {
	private long t1 = 0;
	private long t2 = 0;
	private long t3 = 0;
	private long t4 = 0;

	// 无参构造
	public Traffic() {
	}

	public Traffic(long t1, long t2, long t3, long t4) {
		this.t1 = t1;
		this.t2 = t2;
		this.t3 = t3;
		this.t4 = t4;
	}

	public long getT1() {
		return t1;
	}

	public void setT1(long t1) {
		this.t1 = t1;
	}

	public long getT2() {
		return t2;
	}

	public void setT2(long t2) {
		this.t2 = t2;
	}

	public long getT3() {
		return t3;
	}

	public void setT3(long t3) {
		this.t3 = t3;
	}

	public long getT4() {
		return t4;
	}

	public void setT4(long t4) {
		this.t4 = t4;
	}

	// 实现接口 实现(重写)write和read方法
	public void write(DataOutput out) throws IOException {
		out.writeLong(t1);
		out.writeLong(t2);
		out.writeLong(t3);
		out.writeLong(t4);
	}

	public void readFields(DataInput in) throws IOException {
		this.t1 = in.readLong();
		this.t2 = in.readLong();
		this.t3 = in.readLong();
		this.t4 = in.readLong();
	}

	@Override
	public String toString() {
		return "Traffic [t1=" + t1 + ", t2=" + t2 + ", t3=" + t3 + ", t4=" + t4
				+ "]";
	}

}
package com.myreduce;

import java.io.IOException;

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

/**
 * map阶段
 * @author zzh
 * KEYIN:默认情况下是MapReduce框架所读到的一行文本的偏移量,Long
 * 但是在hadoop中有自己更精简的序列化接口,所以不直接用long而是用LongWritable
 * 
 * VALUE:默认情况下是MapReduce框架所读到的一行文本的内容。String同上 用Text
 * 
 * KEYOUT:是用户自定义逻辑处理写成之后输出数据中的key,String同上Text
 * 
 * VALUEOUT:是用户自定义逻辑处理写成之后输出数据中的value 再此处因为输出四个数据,所以用自定义的Traffic
 */
public class TrafficMapper extends Mapper{
	/*
	 * map阶段的业务逻辑就写在自己定义的map()方法中
	 * 把读入的文件解析成key value对。 对输入的文件每一行解析为key value对
	 * 每个键值对都会调用一次我们定义的map()方法
	 */
	@Override
	protected void map(LongWritable key, Text value,
			Mapper.Context context)
			throws IOException, InterruptedException {
			//把读入的value转换成字符串 根据TAb键把一行分隔成单个的单词
			String[] values = value.toString().split("\t");
			Text outkey = new Text(values[1]);
			long t1 = Long.parseLong(values[6]);
			long t2 = Long.parseLong(values[7]);
			long t3 = Long.parseLong(values[8]);
			long t4 = Long.parseLong(values[9]);
			Traffic tf = new Traffic();
			tf.setT1(t1);
			tf.setT2(t2);
			tf.setT3(t3);
			tf.setT4(t4);
			context.write(outkey, tf);
	}
	
}
package com.myreduce;

import java.io.IOException;

import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

public class TrafficReduce extends Reducer{

	@Override
	protected void reduce(Text key, Iterable value,
			Reducer.Context context)
			throws IOException, InterruptedException {
			//reduce任务是把多个map任务的输出合并排序 把相同key的value放入同一个集合中
			//将输入的key value对解析成新的keyvalue对 输出
			//此处的key值不需要动 可以原样输出  相同的key的value进行合并
			int sum1 = 0;
			int sum2 = 0;
			int sum3 = 0;
			int sum4 = 0;
			for(Traffic s : value){
				sum1 += s.getT1();
				sum2 += s.getT2();
				sum3 += s.getT3();
				sum4 += s.getT4();
			}
			context.write(key, new Traffic(sum1,sum2,sum3,sum4));
	}
	
}
package com.myreduce;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
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.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class TrafficApp {
	public static void main(String[] args) throws Exception {
		Configuration conf = new Configuration();
		conf.set("fs.defaultFS", "file:///");
		Job job = Job.getInstance(conf);
		
		//设置job的属性
		job.setJobName("trafficapp");
		job.setJarByClass(Traffic.class);
		job.setInputFormatClass(TextInputFormat.class);
		
		//设置输入输出路径
		FileInputFormat.addInputPath(job, new Path("file:///e:/copy/"));
		FileOutputFormat.setOutputPath(job, new Path("file:///e:/copy/c"));
		
		job.setMapperClass(TrafficMapper.class);
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(Traffic.class);
		
		job.setReducerClass(TrafficReduce.class);
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(Traffic.class);
		
		job.waitForCompletion(true);
	}
}

上述是在本地执行的 我们还要在hadoop集群上去执行 (hdfs 和yarn都需要启动)

把第一个file:注释掉  两个路径改为args[0]    args[1]

打成jar包 传入Linux中   还需要把需要处理的文件传到hdfs上     输入输出路径都要在hdfs上

 $>hadoop jar MyMapReduce.jar com.shulian.mr.WCApp 输入路径 输出路径

总结

今天主要就是会运用自定义的Writable类 理解每一步的过程 能够在hadoop集群上运行即可

理解一下序列化   hadoop的数据对应的java的数据

查看是否传输成功192.168.163.101:8088  8088端口去看整个的运作过程

Hadoop_day07学习笔记_第2张图片
遇到的错误异常

1.抛出数组越界的异常  :原因是分隔符的问题“\t”代表的是table键 我把斜杠打反了

2.甩出一个io异常,数据类型有问题   原因是我把App这个类里面定义Map的输出类型时定义错误

3.没有权限,无法创建文件     原因是我的file没写冒号............

你可能感兴趣的:(Hadoop,MapReduce_02)