Я пытаюсь ознакомиться с заданиями Hadoop / Hbase MapReduce, чтобы иметь возможность их правильно написать.Прямо сейчас у меня есть экземпляр Hbase с таблицей dns с некоторыми записями DNS.Я попытался сделать простой уникальный счетчик доменов, который выводит файл, и это сработало.Прямо сейчас я использую только IntWritable
или Text
, и мне было интересно, возможно ли использовать пользовательские объекты для моего Mapper / Reducer.Я пытался сделать это сам, но я получаю
Error: java.io.IOException: Initialization of all the collectors failed. Error in last collector was :null
at org.apache.hadoop.mapred.MapTask.createSortingCollector(MapTask.java:415)
at org.apache.hadoop.mapred.MapTask.access$100(MapTask.java:81)
at org.apache.hadoop.mapred.MapTask$NewOutputCollector.<init>(MapTask.java:698)
at org.apache.hadoop.mapred.MapTask.runNewMapper(MapTask.java:770)
at org.apache.hadoop.mapred.MapTask.run(MapTask.java:341)
at org.apache.hadoop.mapred.YarnChild$2.run(YarnChild.java:170)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:422)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1869)
at org.apache.hadoop.mapred.YarnChild.main(YarnChild.java:164)
Caused by: java.lang.NullPointerException
at org.apache.hadoop.mapred.MapTask$MapOutputBuffer.init(MapTask.java:1011)
at org.apache.hadoop.mapred.MapTask.createSortingCollector(MapTask.java:402)
... 9 more
Поскольку я новичок в этом, на самом деле я не знаю, что делать.Я предполагаю, что мне нужно реализовать один или несколько интерфейсов или расширить абстрактный класс, но я не могу найти здесь или в Интернете подходящий пример.
Я пытался сделатьпростой счетчик доменов из моей таблицы DNS, но с использованием класса в качестве оболочки над целым числом (только для дидактических целей).Моя Карта класса выглядит следующим образом:
public class Map extends TableMapper<Text, MapperOutputValue> {
private static byte[] columnName = "fqdn".getBytes();
private static byte[] columnFamily = "d".getBytes();
public void map(ImmutableBytesWritable row, Result value, Context context)
throws InterruptedException, IOException {
String fqdn = new String(value.getValue(columnFamily, columnName));
Text key = new Text();
key.set(fqdn);
context.write(key, new MapperOutputValue(1));
}
}
Редуктор :
public class Reduce extends Reducer<Text, MapperOutputValue, Text, IntWritable> {
@Override
public void reduce(Text key, Iterable<MapperOutputValue> values, Context context)
throws IOException, InterruptedException {
int i = 0;
for (MapperOutputValue val : values) {
i += val.getCount();
}
context.write(key, new IntWritable(i));
}
}
И часть моего Driver /Основная функция:
TableMapReduceUtil.initTableMapperJob(
"dns",
scan,
Map.class,
Text.class,
MapperOutputValue.class,
job);
/* Set output parameters */
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
job.setOutputFormatClass(TextOutputFormat.class);
Как я уже говорил, MapperOutputValue - это простой класс, который содержит закрытое целое число, конструктор с параметром, метод получения и метод установки.Я также попытался добавить метод toString
, но он все еще не работает.
Итак, мой вопрос: каков наилучший способ использования пользовательских классов в качестве вывода преобразователя / ввода для редуктора?Также, скажем, я хочу использовать класс с несколькими полями в качестве конечного результата редуктора.Что этот класс должен реализовывать / расширять?Это хорошая идея, или я должен придерживаться использования «примитивов» в качестве IntWritable или Text?
Спасибо!