mapreduce.TextInputFormat hadoop
Я начинающий хадооп. Я натолкнулся на эту пользовательскую программу RecordReader, которая читает 3 строки за раз и выводит число раз, когда 3-строчный ввод был дан мапперу.
Я могу понять, почему используется RecordReader, но я не могу понять, как каждый InputSplit может содержать 3 строки, когда класс входного формата существенно расширяет класс mapreduce.TextInputFormat. И, насколько я понимаю, класс TextInputFormat испускает 1 InputSplit для каждой строки (для каждой \n).
Так как же RecordReader может прочитать 3 строки из каждого InputSplit? Пожалуйста, кто-нибудь объяснит, как это возможно. Заранее спасибо!
1 ответ
Вы должны понимать реализацию TextInputFormat
чтобы найти ответ.
Давайте углубимся в код. Я буду говорить о новом mapreduce API, но "старый" mapred API очень похож.
Как вы сказали, с точки зрения пользователя TextInputFormat
разбивает разделение на записи в соответствии с некоторыми символами новой строки. Давайте проверим реализацию.
Вы можете видеть, что класс почти пуст. Ключевая функция createRecord
который определяется InputFormat
@Override
public RecordReader<LongWritable, Text> createRecordReader(
InputSplit split,
TaskAttemptContext context
) {
return new LineRecordReader();
}
Общий контракт заключается в том, что InputFormat используется для получения RecordReader. Если вы посмотрите внутрь Mapper
а также MapContextImpl
вы увидите, что картограф использует RecordReader только для получения следующего ключа и значения. Он не знает ничего другого.
Mapper:
public void run(Context context) throws IOException, InterruptedException {
setup(context);
while (context.nextKeyValue()) {
map(context.getCurrentKey(), context.getCurrentValue(), context);
}
cleanup(context);
}
MapContextImpl:
@Override
public boolean nextKeyValue() throws IOException, InterruptedException {
return reader.nextKeyValue();
}
Теперь перечитайте внимательно эту ссылку, которую вы предоставили. Вы увидите, что:
NLinesInputFormat
продолжаетсяTextInputFormat
и только переопределитьcreateRecordReader
, В основном, скорее, используяLineReader
Вы предоставляете свой собственныйRecordReader
, Вы хотите расширитьTextInputFormat
а не другой класс выше в иерархии, потому что он уже позаботится обо всем, что делается на этом уровне, и вам может понадобиться (сжатие, неразборный формат и т. д.)NLinesRecordReader
делает реальную работу. Вinitialize
он делает то, что требуется, чтобы получитьInputStream
ищем по правому смещению от предоставленногоInputSplit
, Это также создаетLineReader
тот же, который используетсяTextInputFormat
- в
nextKeyValue
метод, который вы увидите, чтоLineReader.readLine()
вызывается три раза, чтобы получить три строки (плюс некоторая логика для правильной обработки угловых случаев, таких как слишком большая запись, конец строки, конец разделения)
Надеюсь, что это поможет вам. Ключ должен понять общий дизайн API и как каждая часть взаимодействует друг с другом.