我正在处理存储在HBase中的一大组数据。存储在我的列中的许多值实际上是数据的"矢量"——多个值。我开始处理存储多个值的方法是通过ByteBuffer
。由于我知道存储在列族中每一列中的数据类型,所以我编写了一系列类来扩展一个封装在ByteBuffer
周围的基类,并为我提供了一组简单的方法来读取单个值以及在末尾附加附加值。我已经独立于我的HBase项目测试了这个类,它按预期工作。
为了更新我的数据库(几乎每一行都在每次更新中更新),我使用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[]
数组的末尾。我已经创建了一些类,它们以一种相当干净的方式自动处理这一问题,但我仍然很好奇为什么会发生这种情况。
我在使用MapReduce将数据导入HBase时遇到了类似的问题。有垃圾字节附加到我的行键,由于这个代码:
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);
}
}
问题是Text.getBytes()从后端返回实际的字节数组(请参阅Text),而Text对象被MapReduce框架重用。因此,字节数组将包含以前值中的垃圾字符。这个变化为我修复了它:
Put put = new Put(Arrays.copyOf(key.getBytes(), key.getLength()));
如果你在某个地方的工作中使用文本作为你的价值类型,它可能也在做同样的事情。
这是jdk7与jdk6的问题吗?您是否使用两个不同的jvm版本?
可能与playorm用户遇到的东西有关https://github.com/deanhiller/playorm/commit/5e6ede13477a60c2047daaf1f7a7ce55550b0289
Dean