Text.getBytes()返回意外结果

时间:2012-04-26 00:33:51

标签: java serialization unicode encoding hadoop

我从Text构造函数中获得了一些没有任何意义的行为。基本上,如果我从String构造一个Text对象,它不等于我从字节构造的另一个Text对象,即使getBytes()为两个对象返回相同的值。

所以我们得到这样奇怪的东西:

//This succeeds
assertEquals(new Text("ACTACGACCA_0"), new Text("ACTACGACCA_0")); 
//This succeeds
assertEquals((new Text("ACTACGACCA_0")).getBytes(), (new Text("ACTACGACCA_0")).getBytes()); 
//This fails.  Why?
assertEquals(new Text((new Text("ACTACGACCA_0")).getBytes()), new Text("ACTACGACCA_0"));  

当我尝试访问hashmap时会出现这种情况。在这里,我正在尝试根据org.apache.hadoop.hbase.KeyValue.getRow()返回的值进行查找:

//This succeeds
assertEquals((new Text("ACTACGACCA_0")).getBytes(), keyValue.getRow()); 
//This returns a value
hashMap.get(new Text("ACTACGACCA_0"));  
//This returns null.  Why?
hashMap.get(new Text(keyValue.getRow()));  

那么这里发生了什么,我该如何应对呢?这与编码有关吗?

更新:问题已解决

感谢克里斯指出我正确的方向。所以,一点背景:从调用htable.put()中捕获keyValue对象(使用Mockito ArgumentCaptor)。基本上,我有这段代码:

byte[] keyBytes = matchRow.getKey().getBytes();
RowLock rowLock = hTable.lockRow(keyBytes);                         

Get get = new Get(keyBytes, rowLock);               
SetWritable<Text> toWrite = new SetWritable<Text>(Text.class);
toWrite.getValues().addAll(matchRow.getMatches(hTable, get));

Put put = new Put(keyBytes, rowLock);
put.add(Bytes.toBytes(MatchesByHaplotype.MATCHING_COLUMN_FAMILY), Bytes.toBytes(MatchesByHaplotype.UID_QUALIFIER), 
        SERIALIZATION_HELPER.serialize(toWrite));               
hTable.put(put);

其中matchRow.getKey()返回一个文本对象。你在这看到问题了吗?我正在添加所有字节,包括无效字节。所以我创建了一个很好的辅助函数来执行此操作:

public byte[] getValidBytes(Text text) {
    return Arrays.copyOf(text.getBytes(), text.getLength());
}

并将该块的第一行更改为:

byte[] keyBytes = SERIALIZATION_HELPER.getValidBytes(matchRow.getKey());

问题解决了!回想起来:哇,多么讨厌的虫子!我认为它归结为Text.getBytes()的行为非常不友好。它不仅会返回您可能没有预期的内容(无效字节),Text对象也没有返回有效字节的函数!你会认为这是一个常见的用例。也许他们将来会添加这个?

1 个答案:

答案 0 :(得分:3)

出于同样的原因,以下情况失败:

Assert.assertEquals((new Text("ACTACGACCA_0")).getLength(), (new Text("ACTACGACCA_0")).getBytes().length);

getBytes()返回后备字节数组,但根据API,字节仅有效Text.getLength();

是的,这与编码有关 - CharsetEncoder.encode方法使用ByteBuffer,其大小最初分配为12 * 1.1字节(13)的长度,但实际有效字节数仍然只有12(如你只使用ASCII字符。)