如何在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