如何在Hadoop的map reduce作业中按自定义比较器对键进行排序?

如何在Hadoop的map reduce作业中按自定义比较器对键进行排序?,hadoop,mapreduce,comparator,hadoop2,Hadoop,Mapreduce,Comparator,Hadoop2,考虑一下这个类:(来自Hadoop:The definitive guide3rd edition): import java.io.*; 导入org.apache.hadoop.io.*; 公共类TextPair实现了writeablecompare{ 私人文本优先; 私人文本第二; 公共文本对(){ 设置(新文本(),新文本()); } 公共文本对(字符串第一,字符串第二){ 设置(新文本(第一)、新文本(第二)); } 公共文本对(文本第一,文本第二){ 设置(第一,第二); } 公共无效

考虑一下这个
:(来自
Hadoop:The definitive guide
3rd edition):

import java.io.*;
导入org.apache.hadoop.io.*;
公共类TextPair实现了writeablecompare{
私人文本优先;
私人文本第二;
公共文本对(){
设置(新文本(),新文本());
}
公共文本对(字符串第一,字符串第二){
设置(新文本(第一)、新文本(第二));
}
公共文本对(文本第一,文本第二){
设置(第一,第二);
}
公共无效集(文本第一,文本第二){
this.first=first;
这个秒=秒;
}
公共文本getFirst(){
先返回;
}
公共文本getSecond(){
返回第二;
}
@凌驾
public void write(DataOutput out)引发IOException{
首先,写出;
第二,写出;
}
@凌驾
public void readFields(DataInput in)引发IOException{
首先,读取字段(in);
第二,readFields(in);
}
@凌驾
公共int hashCode(){
返回first.hashCode()*163+second.hashCode();
}
@凌驾
公共布尔等于(对象o){
if(文本对的o实例){
text对tp=(text对)o;
返回first.equals(tp.first)和&second.equals(tp.second);
}
返回false;
}
@凌驾
公共字符串toString(){
返回第一个+“\t”+第二个;
}
@凌驾
公共整数比较(文本对tp){
int cmp=第一比较(tp第一);
如果(cmp!=0){
返回cmp;
}
返回second.compareTo(tp.second);
}
//^^^文本对
//vv文本对比较程序
公共静态类比较器扩展了WritableComparator{
私有静态最终文本.Comparator Text_Comparator=新文本.Comparator();
公共比较器(){
super(TextPair.class);
}
@凌驾
公共整数比较(字节[]b1,整数s1,整数l1,
字节[]b2,整数s2,整数l2){
试一试{
int firstL1=WritableUtils.decodeVIntSize(b1[s1])+readVInt(b1,s1);
int firstL2=WritableUtils.decodeVIntSize(b2[s2])+readVInt(b2,s2);
int cmp=文本\比较器。比较(b1、s1、firstL1、b2、s2、firstL2);
如果(cmp!=0){
返回cmp;
}
返回文本\u比较器。比较(b1,s1+firstL1,l1-firstL1,
b2,s2+firstL2,l2-firstL2);
}捕获(IOE异常){
抛出新的IllegalArgumentException(e);
}
}
}
静止的{
WritableComparator.define(TextPair.class,new Comparator());
}
//^^TextPairComparator
//vv TEXTPAIRFIRST比较器
公共静态类FirstComparator扩展了WritableComparator{
私有静态最终文本.Comparator Text_Comparator=新文本.Comparator();
公共FirstComparator(){
super(TextPair.class);
}
@凌驾
公共整数比较(字节[]b1,整数s1,整数l1,
字节[]b2,整数s2,整数l2){
试一试{
int firstL1=WritableUtils.decodeVIntSize(b1[s1])+readVInt(b1,s1);
int firstL2=WritableUtils.decodeVIntSize(b2[s2])+readVInt(b2,s2);
返回文本_COMPARATOR.compare(b1、s1、firstL1、b2、s2、firstL2);
}捕获(IOE异常){
抛出新的IllegalArgumentException(e);
}
}
@凌驾
公共整数比较(可写可比a、可写可比b){
if(文本对的a实例和文本对的b实例){
return((TextPair)a.first.compareTo((TextPair)b.first);
}
返回super.compare(a,b);
}
}
//^^TextPairFirstComparator
//vv文本对
}
//^^^文本对
定义了两种
比较器
: 一种是按
第一个
排序,然后是
第二个
,这是默认的
比较器。
另一种是仅按
first
排序,这是
firstComparator。

如果我必须使用firstComparator对密钥进行排序,我该如何实现? 也就是说,如何用我在上面定义的
第一个比较器
覆盖我的默认比较器

其次,既然
map
作业的输出未
排序,我将如何
unitTest
这一点

如果我必须使用firstComparator对密钥进行排序,我该如何实现?也就是说,如何用我上面定义的第一个比较器覆盖我的默认比较器

我假设您期望一个类似setComparator(firstComparator)的方法。据我所知,没有这种方法。使用表示键的
Writeable
类型的
compareTo()
对键进行排序(在映射器侧)。在您的例子中,
compareTo()
方法检查第一个值,然后检查第二个值。换句话说,键将按第一个值排序,然后同一组中的键(即具有相同的第一个值)将按其第二个值排序

总而言之,这意味着您的键将始终按第一个值排序(+如果第一个值不能做出决定,则按第二个值排序)。这反过来意味着不需要使用不同的比较器(
firstComparator
),它只查看第一个值,因为这已经通过
TextPair
类的
compareTo()
方法实现了

另一方面,如果
firstComparator
对键进行完全不同的排序,唯一的解决方案是将
firstComparator
中的逻辑移动到表示键的
writeable
类的
compareTo()
方法。我看不出你为什么不那样做。如果您已经有了
firstComparator
并希望重用它,则可以在
TexPair
可写的
compareTo()
方法中实例化并调用它

您可能还想看看
GroupingComparator
,它用于确定在同一个应用程序中同时使用哪些键
import java.io.*;
import org.apache.hadoop.io.*;

public class TextPair implements WritableComparable<TextPair> {

  private Text first;
  private Text second;

  public TextPair() {
    set(new Text(), new Text());
  }

  public TextPair(String first, String second) {
    set(new Text(first), new Text(second));
  }

  public TextPair(Text first, Text second) {
    set(first, second);
  }

  public void set(Text first, Text second) {
    this.first = first;
    this.second = second;
  }

  public Text getFirst() {
    return first;
  }

  public Text getSecond() {
    return second;
  }

  @Override
  public void write(DataOutput out) throws IOException {
    first.write(out);
    second.write(out);
  }

  @Override
  public void readFields(DataInput in) throws IOException {
    first.readFields(in);
    second.readFields(in);
  }

  @Override
  public int hashCode() {
    return first.hashCode() * 163 + second.hashCode();
  }

  @Override
  public boolean equals(Object o) {
    if (o instanceof TextPair) {
      TextPair tp = (TextPair) o;
      return first.equals(tp.first) && second.equals(tp.second);
    }
    return false;
  }

  @Override
  public String toString() {
    return first + "\t" + second;
  }

  @Override
  public int compareTo(TextPair tp) {
    int cmp = first.compareTo(tp.first);
    if (cmp != 0) {
      return cmp;
    }
    return second.compareTo(tp.second);
  }
  // ^^ TextPair

  // vv TextPairComparator
  public static class Comparator extends WritableComparator {

    private static final Text.Comparator TEXT_COMPARATOR = new Text.Comparator();

    public Comparator() {
      super(TextPair.class);
    }

    @Override
    public int compare(byte[] b1, int s1, int l1,
                       byte[] b2, int s2, int l2) {

      try {
        int firstL1 = WritableUtils.decodeVIntSize(b1[s1]) + readVInt(b1, s1);
        int firstL2 = WritableUtils.decodeVIntSize(b2[s2]) + readVInt(b2, s2);
        int cmp = TEXT_COMPARATOR.compare(b1, s1, firstL1, b2, s2, firstL2);
        if (cmp != 0) {
          return cmp;
        }
        return TEXT_COMPARATOR.compare(b1, s1 + firstL1, l1 - firstL1,
                                       b2, s2 + firstL2, l2 - firstL2);
      } catch (IOException e) {
        throw new IllegalArgumentException(e);
      }
    }
  }

  static {
    WritableComparator.define(TextPair.class, new Comparator());
  }
  // ^^ TextPairComparator

  // vv TextPairFirstComparator
  public static class FirstComparator extends WritableComparator {

    private static final Text.Comparator TEXT_COMPARATOR = new Text.Comparator();

    public FirstComparator() {
      super(TextPair.class);
    }

    @Override
    public int compare(byte[] b1, int s1, int l1,
                       byte[] b2, int s2, int l2) {

      try {
        int firstL1 = WritableUtils.decodeVIntSize(b1[s1]) + readVInt(b1, s1);
        int firstL2 = WritableUtils.decodeVIntSize(b2[s2]) + readVInt(b2, s2);
        return TEXT_COMPARATOR.compare(b1, s1, firstL1, b2, s2, firstL2);
      } catch (IOException e) {
        throw new IllegalArgumentException(e);
      }
    }

    @Override
    public int compare(WritableComparable a, WritableComparable b) {
      if (a instanceof TextPair && b instanceof TextPair) {
        return ((TextPair) a).first.compareTo(((TextPair) b).first);
      }
      return super.compare(a, b);
    }
  }
  // ^^ TextPairFirstComparator

// vv TextPair
}
// ^^ TextPair