hbase bulk load相關源碼簡析之PutSortReducer、KeyValueSortReducer

轉載請註明出處: http://blog.csdn.net/lonelytrooper/article/details/17040895

PutSortReducer:

  1. // 對map階段傳遞過來的puts中的KVs做排序,並將有序的KVs寫到輸出流(最終寫的類是HFileWriterV1或HFileWriterV2的append方法)...  
  2. public class PutSortReducer extends  
  3.         Reducer<ImmutableBytesWritable, Put, ImmutableBytesWritable, KeyValue> {  
  4.   
  5.     @Override  
  6.     protected void reduce(ImmutableBytesWritable row, java.lang.Iterable<Put> puts,  
  7.             Reducer<ImmutableBytesWritable, Put, ImmutableBytesWritable, KeyValue>.Context context)  
  8.             throws java.io.IOException, InterruptedException {  
  9.         // although reduce() is called per-row, handle pathological case  
  10.         // 設定一個RAM的閥值,用於應對非常規的情況.. 默認值2L * (1 << 30)爲Integer.MAX_VALUE+1  
  11.         long threshold = context.getConfiguration().getLong("putsortreducer.row.threshold",  
  12.                 2L * (1 << 30));  
  13.         Iterator<Put> iter = puts.iterator();  
  14.         while (iter.hasNext()) {  
  15.             TreeSet<KeyValue> map = new TreeSet<KeyValue>(KeyValue.COMPARATOR); // KVComparator  
  16.             long curSize = 0;  
  17.             // stop at the end or the RAM threshold  
  18.             // 用curSize累計當前puts的size,但這個size不能超過threshold...  
  19.             while (iter.hasNext() && curSize < threshold) {  
  20.                 Put p = iter.next();  
  21.                 for (List<KeyValue> kvs : p.getFamilyMap().values()) {  
  22.                     for (KeyValue kv : kvs) {  
  23.                         map.add(kv);  
  24.                         curSize += kv.getLength();  
  25.                     }  
  26.                 }  
  27.             }  
  28.             // 記錄已讀取的map中的KV的個數,並將curSize轉成易讀的KB,MB,GB..  
  29.             context.setStatus("Read " + map.size() + " entries of " + map.getClass() + "("  
  30.                     + StringUtils.humanReadableInt(curSize) + ")");  
  31.             int index = 0;  
  32.             // 將當前有序的KV寫到輸出流..  
  33.             for (KeyValue kv : map) {  
  34.                 context.write(row, kv);  
  35.                 if (index > 0 && index % 100 == 0// 記錄進度,每100個記錄一次..  
  36.                     context.setStatus("Wrote " + index);  
  37.             }  
  38.   
  39.             // if we have more entries to process  
  40.             //如果居然還有put沒處理完..我們會通過context.write(null, null)強刷.. 這會關閉當前的Writer(StoreFile.Writer),並形成了一個StoreFile。  
  41.             //在外層的下次循環中,會繼續處理餘下的數據,並創建新的StoreFile的Writer。 換言之,這種情況下相同rowkey的數據會被寫到不同的StoreFile中...  
  42.             //細節部分可以看下HFileOutputFormat下RecordWriter類下的write方法..  
  43.             if (iter.hasNext()) {  
  44.                 // force flush because we cannot guarantee intra-row sorted  
  45.                 // order  
  46.                 context.write(nullnull);  
  47.             }  
  48.         }  
  49.     }  
  50. }  

KeyValueSortReducer:
  1. // 類比PutSortReducer,對map傳遞過來的KVs進行排序,並將有序的KVs寫到輸出流...  
  2. // 如果一行包含的列非常多的話,有oom的風險..  
  3. public class KeyValueSortReducer extends Reducer<ImmutableBytesWritable, KeyValue, ImmutableBytesWritable, KeyValue> {  
  4.   protected void reduce(ImmutableBytesWritable row, java.lang.Iterable<KeyValue> kvs,  
  5.       org.apache.hadoop.mapreduce.Reducer<ImmutableBytesWritable, KeyValue, ImmutableBytesWritable, KeyValue>.Context context)  
  6.   throws java.io.IOException, InterruptedException {  
  7.     TreeSet<KeyValue> map = new TreeSet<KeyValue>(KeyValue.COMPARATOR);  
  8.     for (KeyValue kv: kvs) {  
  9.       map.add(kv.clone());  
  10.     }  
  11.     context.setStatus("Read " + map.getClass());  
  12.     int index = 0;  
  13.     for (KeyValue kv: map) {  
  14.       context.write(row, kv);  
  15.       if (index > 0 && index % 100 == 0) context.setStatus("Wrote " + index);  
  16.     }  
  17.   }  
  18. }  

簡單說下TotalOrderPartitioner和SimpleTotalOrderPartitioner:

TotalOrderPartitioner:

做全排序的東東,Hbase中的TOP其實就是Hadoop中TOP的直接拷貝,通過從外部文件中讀取分區點來實現。 在bulk load中,這個外部文件即爲從HTable中獲取的region的startKeys處理之後得到的split points,這個split points文件被寫到了路徑Path partitionsPath = new Path(job.getWorkingDirectory(), "partitions_" + UUID.randomUUID())。

SimpleTotalOrderPartitioner:

簡單的做全排序的東東,原則是根據輸入的startkey和endkey進行均分,區間是左閉右開。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章