MRUnit передает значения в объект результата hbase

Я тестирую свой картограф с MRUnit. Я передаю ключ и список значений в качестве входных данных для картографа из тестового класса. Проблема в :

String key=1234_abc;
ArrayList<KeyValue> list = new ArrayList<KeyValue>();
KeyValue k1 = new KeyValue(Bytes.toBytes(key),"cf".getBytes(), "Val1".getBytes(),Bytes.toBytes("abc.com"));
KeyValue k2 = new KeyValue(Bytes.toBytes(key), "cf".getBytes(), "Val2".getBytes(),Bytes.toBytes("165"));
Result result = new Result(list);
mapDriver.withInput(key, result); 

Проблема в том, что в результирующем объекте сохраняется только первое ключевое значение. Остальные сохраняются как null.


person user2401464    schedule 04.04.2014    source источник


Ответы (2)


Проблема в том, что HBase хранит столбцы в лексикографическом порядке. Похоже, что конструктор Result(KeyValue[] kvs) или Result(List kvs) ожидает в одном и том же порядке.

Вот решение!

TreeSet<KeyValue> set = new TreeSet<KeyValue>(KeyValue.COMPARATOR);

byte[] row = Bytes.toBytes("row01");
byte[] cf = Bytes.toBytes("cf");
set.add(new KeyValue(row, cf, "cone".getBytes(), Bytes.toBytes("row01_cone_one")));
set.add(new KeyValue(row, cf, "ctwo".getBytes(), Bytes.toBytes("row01_ctwo_two")));
set.add(new KeyValue(row, cf, "cthree".getBytes(), Bytes.toBytes("row01_cthree_three")));
set.add(new KeyValue(row, cf, "cfour".getBytes(), Bytes.toBytes("row01_cfour_four")));
set.add(new KeyValue(row, cf, "cfive".getBytes(), Bytes.toBytes("row01_cfive_five")));
set.add(new KeyValue(row, cf, "csix".getBytes(), Bytes.toBytes("row01_csix_six")));

KeyValue[] kvs = new KeyValue[set.size()];
set.toArray(kvs);

Result result = new Result(kvs);
mapDriver.withInput(key, result);

Надеюсь, это поможет!

person Sakthivel    schedule 19.12.2014
comment
Чувак, круто! Сэкономил мне много работы, издеваясь над классом «Результат». - person LBogaardt; 06.01.2016

Я только что закончил около 6 часов боли по этому вопросу и, наконец, обнаружил проблему. Похоже, это ошибка в классе org.apache.hadoop.hbase.client.Result, по крайней мере, для версии HBase, которую я использую (0.94.18).

// The below line of code was failing for me when running locally under MRUnit
// but it seemed to succeed when running in production on my cluster.
// org.apache.hadoop.hbase.client.Result result passed in to this method.
Bytes.toString(result.getValue(Constants.CF1, Constants.REG_STATUS_FLAG_BYTES));

result.getValue() вызывает getColumnLatest(), который содержит вызов binarySearch(). Метод binarySearch() кажется ошибочным и почти всегда возвращает неверный индекс. getColumnLatest() дважды проверяет, что он действительно нашел правильное значение KeyValue, убеждаясь, что семейство и квалификатор совпадают. Обычно они не совпадают, и возвращается ноль.

В итоге я повторно реализовал метод getValue() и 3 метода, которые он использует, а затем переключился на функционально правильную реализацию в моем модульном тесте. Может быть лучший способ добиться этого, но уже поздно, и это то, что я придумал (и это решает проблему):

// Usage: Pass the Result into the newly created getValue() method, rather than
// calling getValue() on the Result object.
Bytes.toString(getValue(result, Constants.CF1, Constants.REG_STATUS_FLAG_BYTES));

// Reimplemented Methods:
private byte[] getValue(Result result, byte [] family, byte [] qualifier) {
  KeyValue kv = getColumnLatest(result, family, qualifier);
  if (kv == null) {
    return null;
  }
  return kv.getValue();
}

private KeyValue getColumnLatest(Result result,  byte[] family, byte[] qualifier) {    
  KeyValue [] kvs = result.raw(); // side effect possibly.
  if (kvs == null || kvs.length == 0) {
    return null;
  }
  //int pos = binarySearch(kvs, family, qualifier);
  int pos = linearSearch(kvs, family, qualifier);
  if (pos == -1) {
    return null;
  }
  KeyValue kv = kvs[pos];
  if (kv.matchingColumn(family, qualifier)) {
    return kv;
  }
  return null;
}

private int linearSearch(final KeyValue [] kvs, final byte [] family,
  final byte [] qualifier) {

  int pos = -1;
  int index = 0;
  for (KeyValue kv : kvs) {
    if (byteArraysEqual(family, kv.getFamily()) && byteArraysEqual(qualifier, kv.getQualifier())) {
      pos = index;
      break;
    }
    index++;
  }
  return pos;
}

private boolean byteArraysEqual(final byte[] ba1, final byte[] ba2) {    
  if (ba1 == null || ba2 == null) {
    return false;
  }

  if (ba1.length != ba2.length) {
    return false;
  }

  for (int i = 0; i < ba1.length; i++) {
    if (ba1[i] != ba2[i]) {
      return false;
    }
  }

  return true;
}
person Eric Minor    schedule 11.12.2014