MapReduce中自定义数据类型作为key

    在MapReduce编程模型中key通常是用来排序和划分的。排序是指按照key的大小顺序将 <k,v> 键值对排序,划分是指按照key的hashcode值将 <k,v>划分到指定的Reducer节点上。

    MapReduce中的key类型必须实现WritableComparable接口,为了方便用户使用,Hadoop提供有一些内置的key类型。常见的key类型有 IntWritable 、LongWritable 、Text、FloatWritable等。但有时我们还需使用自己定义的数据类型作为key。

    下面小编就用数据表求交集的例子来介绍自定义数据类型怎么作为key。

有如下两个数据表,数据关系属于同一模型,字段有 id、name 、age 、grade。数据表table1和table2中的内容如下所示。


    


    求交集的目的是输出两个表中相同的记录。如上table1和table2所示,应该输出id为1、2的记录。

    求交集的思想为在Map阶段对每一条记录r输出 <r,1>,然后在Reduce阶段汇总计数,将计数为2的记录r输出即可。

    我们用一个Stu类来存储一条记录,并将Stu类作为key使用,Stu类要实现WritableComparable接口,要注意一下几点:


  1. 必须有一个无参的构造函数。

  2. 必须重写WritableComparable接口的hashCode()方法和equals()方法以及compareTo()方法。


Stu类的代码如下:


package Eg1;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.WritableComparable;

/**
 * Stu类设计
 * @author liuchen
 */
public class Stu implements WritableComparable<Stu>
{
	private int id;
	private String name;
	private int age;
	private int grade;
	//无参的构造函数必不可少
	public Stu(){	
	}
	public Stu(int a, String b, int c, int d){
		this.id = a;
		this.name = b;
		this.age = c;
		this.grade = d;
	}
	public void readFields(DataInput in) throws IOException {
		this.id = in.readInt();
		this.name = in.readUTF();
		this.age = in.readInt();
		this.grade = in.readInt();	
	}
	public void write(DataOutput out) throws IOException {
		out.writeInt(id);
		out.writeUTF(name);
		out.writeInt(age);
		out.writeInt(grade);
	}
	//按照id降序排列
	public int compareTo(Stu o) {
		return this.id >= o.id ? -1 : 1 ;
	}
	public int hashCode() {
            return this.id + this.name.hashCode() + this.age + this.grade;
	}
	public boolean equals(Object obj) {
	    if (!(obj instanceof Stu)) {  
                return false;  
            }else{  
        	Stu r = (Stu) obj; 
    		if (this.id == r.id && this.name.equals(r.name) && this.age == r.age && this.grade == r.grade){
    	            return true;
    		}else{
    	            return false;
    		}
            }	 
	}
	
	public String toString() {
		return Integer.toString(id) + "\t" + name + "\t" + Integer.toString(age) + "\t" + Integer.toString(grade);
	}
}


Map阶段的map()函数如下:


protected void map(LongWritable key, Text value,Context context)throws IOException, InterruptedException {
		final IntWritable one = new IntWritable(1);
		String[] arr = value.toString().split("\t");
		Stu stu = new Stu(Integer.parseInt(arr[0]),arr[1],Integer.parseInt(arr[2]),Integer.parseInt(arr[3]));
		context.write(stu,one);
}

Reduce阶段的reduce()函数如下:


protected void reduce(Stu arg0, Iterable<IntWritable> arg1,Context arg2)throws IOException, InterruptedException {
		int sum = 0;
		for(IntWritable val : arg1){
			sum += val.get();
		}
		if(sum == 2){
			arg2.write(arg0,NullWritable.get());
		}
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章