2012-02-17 54 views
3

我正在處理HBase中存儲的大量數據。存儲在我的列中的許多值實際上是數據的「向量」 - 多個值。我開始處理存儲多個值的方式是通過ByteBuffer。由於我知道存儲在我的列族的每一列中的數據類型,因此我編寫了一系列擴展基類的類,這些類包裝在ByteBuffer中,併爲我提供了一套簡單的方法來讀取各個值以及將附加值附加到結束。我已經獨立於我的HBase項目測試過這個類,它按預期工作。額外的字節附加到由HBase返回的值TableMapper

爲了更新我的數據庫(每個更新中幾乎每行都更新),我使用一個TableMapper mapreduce作業遍歷數據庫中的每一行。我的每個映射器(在我的集羣中有六個映射器)將整個更新文件(很少超過50MB)加載到內存中,然後在迭代它時更新每個行ID。

我遇到的問題是每當我從Result對象中取出一個數據值時,它有4個字節附加到它的末尾。這使我的更新變得困難,因爲我不確定是否期望這個「填充」每次多出4個字節,或者是否可以擴大到更大/更小。由於我將此加載到我的ByteBuffer包裝器中,所以沒有填充是很重要的,因爲那樣會在我附加額外的數據點時導致數據中存在空隙,這將使得以後無法讀取它們而出錯。

我寫了一個測試,通過創建一個測試表和類來確認我的假設。該表每列只有一個數據點(單個雙 - 我已確認進入的字節的長度是8),並且我寫下了以下代碼以檢索並檢查它。

HTable table = new HTable("test"); 
byte[] rowId = Bytes.toBytes("myid"); 
Get get = new Get(rowId); 
byte[] columnFamily = Bytes.toBytes("data"); 
byte[] column = Bytes.toBytes("column"); 
get.addColumn(columnFamily, column); 
Result = table.get(get); 
byte[] value = result.value(); 
System.out.printlin("Value size: " + value.length); 
double doubleVal = Bytes.toDouble(value); 
System.out.println("Fetch yielded: " + doubleVal); 
byte[] test = new byte[8]; 
for (int i = 0; i < value.length - 4; i++) 
    blah[i] = value[i]; 
double dval = Bytes.toDouble(test); 
System.out.println("dval: " + dval); 
table.close() 

導致:

Value size: 12 
Fetch yielded: 0.3652 
dval: 0.3652 

這些值是可以預期的。

有關如何解決此問題的任何想法?我意識到像Avro這樣的序列化引擎的存在,但我試圖暫時避免使用它們,我的數據非常直觀,以至於我覺得我不應該這樣做。

編輯:我繼續前進,截斷我的數據的最大公倍數我的數據類型的大小。根據我的經驗,這些額外的字節專門添加到我的byte[]陣列的末尾。我已經做了幾個能夠以相當乾淨的方式自動處理這個問題的類,但我仍然好奇爲什麼會發生這種情況。

回答

2

使用的MapReduce到HBase的導入數據時,我也有類似的問題。由於以下代碼,我的rowkeys上會附加垃圾字節:

public class MyReducer extends TableReducer<Text, CustomWritable, Text> { 

    protected void reduce(Text key, Iterable<CustomWritable> values, Context context) throws IOException, InterruptedException { 
     // only get first value for the example 
     CustomWritable value = values.iterator().next(); 
     Put put = new Put(key.getBytes()); 
     put.add(columnFamily, columnName, value.getBytes()); 
     context.write(outputKey, put); 
     } 
    } 

問題在於文本。getBytes()從後端返回實際的字節數組(見Text),而Text對象被MapReduce框架重用。因此,字節數組將具有它保存的先前值的垃圾字符。這個變化對我來說是固定的:

Put put = new Put(Arrays.copyOf(key.getBytes(), key.getLength())); 

如果你在某處使用Text作爲你的值類型,它可能會做同樣的事情。