您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關Hadoop中如何自定義類型,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
代碼如下。
public interface Comparable<T> { public int compareTo(T o); }
規定了對象內部比較的方法
public interface Comparator<T> { int compare(T o1, T o2); boolean equals(Object obj); }
定義外部比較器的基本方法,其中equals是用來確定兩個比較器是否相等
關于對象內部比較和外部比較這兩個接口的區別和使用場景如下:
個人總結:
Comparable是對象內部固有的比較,一個類的不同對象肯定需要很自然的比較,無論使用在任何地方 Comparator是外部比較,在不改變對象內部固有的比較標準的前提下,增加新的比較行為, 尤其是對已有的類型,String,Integer等,如果我們想要不同的比較行為,例如絕對值比較,那么我們不能修改這寫類固有的比較標準,而是加入自定義的外部比較器, 在外部比較器中定義新的比較規則,同時在需要比較的地方,插入我們自定義的外部比較器實例。
我們知道hadoop中有自定義類型,需要實現, WritableComparable接口,而WritableComparable接口繼承之一便是Comparable接口。
因此,自定義的類型需要實現compareTo方法
如,LongWrite.class
@Override public int compareTo(LongWritable o) { long thisValue = this.value; long thatValue = o.value; return (thisValue<thatValue ? -1 : (thisValue==thatValue ? 0 : 1)); }
但是hadoop并沒有直接使用這個基于對象內部比較機制,對需要排序比較的地方進行key的排序,而是借助外部比較器,統一介入的。 hadoop中的外部比較器, WritableComparator。
public static WritableComparator get( Class<? extends WritableComparable> c, Configuration conf) { WritableComparator comparator = comparators.get(c); if (comparator == null) { // force the static initializers to run forceInit(c); // look to see if it is defined now comparator = comparators.get(c); // if not, use the generic one if (comparator == null) { comparator = new WritableComparator(c, conf, true); } } // Newly passed Configuration objects should be used. ReflectionUtils.setConf(comparator, conf); return comparator; }
該方法會被Job調用,獲得當前類型對應的外部比較器實例。WritableComparator內部有緩存,其中會緩存類型和其對應的外部比較器。get方法會從緩存中取得類型對應的外部比較器,如果取得為空,則手動生成一個外部比較器,
外部比較器,默認的比較方法是按照對象的內部比較標準進行的。
@SuppressWarnings("unchecked") public int compare(WritableComparable a, WritableComparable b) { return a.compareTo(b); } @Override public int compare(Object a, Object b) { return compare((WritableComparable)a, (WritableComparable)b); }
但是,hadoop在使用這個外部比較器的地方的,使用方式是:(例如,MapOutputBuffer,map端spill)
public int compare(final int mi, final int mj) { final int kvi = offsetFor(mi % maxRec); final int kvj = offsetFor(mj % maxRec); final int kvip = kvmeta.get(kvi + PARTITION); final int kvjp = kvmeta.get(kvj + PARTITION); // sort by partition if (kvip != kvjp) { return kvip - kvjp; } // sort by key return comparator.compare(kvbuffer, kvmeta.get(kvi + KEYSTART), kvmeta.get(kvi + VALSTART) - kvmeta.get(kvi + KEYSTART), kvbuffer, kvmeta.get(kvj + KEYSTART), kvmeta.get(kvj + VALSTART) - kvmeta.get(kvj + KEYSTART)); }
使用的是外部比較器的這個方法,如下
@Override public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) { try { buffer.reset(b1, s1, l1); // parse key1 key1.readFields(buffer); buffer.reset(b2, s2, l2); // parse key2 key2.readFields(buffer); } catch (IOException e) { throw new RuntimeException(e); } return compare(key1, key2); // compare them }
而這個方法默認也是使用對象內部比較的標準。
在考慮性能的時候,需要將這個方法的默認行為改成基于bytes字節的比較,那么就需要用戶自己寫一個外部比較類的子類,并手動放到WritableComparator類中的內部緩存。
這種手動放入到緩存的過程,在自定義類型中完成,(LongWritable為例) (1)自定義外部比較器的子類。
public static class Comparator extends WritableComparator { public Comparator() { super(LongWritable.class); } @Override public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) { long thisValue = readLong(b1, s1); long thatValue = readLong(b2, s2); return (thisValue<thatValue ? -1 : (thisValue==thatValue ? 0 : 1)); } }
(2)手動注入到緩存中
static { // register default comparator WritableComparator.define(LongWritable.class, new Comparator()); }
這樣,就改變了外部比較器默認的比較標準,按照用戶自定義的compare方法進行比較。
那么,什么時候要自定義外部比較器呢?
1)效率考慮,如上所述 2)排序的規則發生變化,所有需要排序的地方,可以指定外部比較器,讓其發生比較規則的改變(默認的比較都是自定義類型中的外部比較器比較規則)
比如,二次排序等。
上述就是小編為大家分享的Hadoop中如何自定義類型了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。