Дополнительные байты добавляются к значениям, возвращаемым HBase TableMapper - PullRequest
3 голосов
/ 18 февраля 2012

Я работаю с большим набором данных, хранящихся в HBase. Многие из значений, хранящихся в моих столбцах, на самом деле являются «векторами» данных - множественными значениями. Я решил установить хранение нескольких значений через ByteBuffer. Так как я знаю тип данных, хранящихся в каждом столбце в моих семействах столбцов, я написал серию классов, расширяющих базовый класс, который охватывает ByteBuffer и дает мне простой набор методов для чтения отдельных значений, а также добавления дополнительных значения до конца. Я протестировал этот класс независимо от моего проекта HBase, и он работает, как и ожидалось.

Чтобы обновить мою базу данных (почти каждая строка обновляется в каждом обновлении), я использую задание TableMapper mapreduce для перебора каждой строки в моей базе данных. Каждый из моих картографов (в моем кластере их шесть) загружает весь файл обновления (редко более 50 МБ) в память, а затем обновляет каждый идентификатор строки при его итерации по нему.

Проблема, с которой я сталкиваюсь , заключается в том, что каждый раз, когда я извлекаю значение данных из объекта 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 ]

2 голосов
/ 02 октября 2013

У меня была похожая проблема при импорте данных с использованием 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()));

Если вы используете текст в качестве типа значения где-то в своей работе, это может быть то же самое.

0 голосов
/ 05 июня 2013

Это проблема jdk7 против jdk6? Вы в двух разных версиях JVM?

может быть связано с тем, с чем столкнулся пользователь playorm https://github.com/deanhiller/playorm/commit/5e6ede13477a60c2047daaf1f7a7ce55550b0289

Dean

...