Как получить имя входного файла в Mapper в программе Hadoop?

Как я могу получить имя входного файла внутри mapper? У меня есть несколько входных файлов, хранящихся во входной директории, каждый из которых может читать другой файл, и мне нужно знать, какой файл читатель просматривал.

Сначала вам нужно получить разделение ввода, используя новый API mapreduce, это будет сделано следующим образом:

context.getInputSplit(); 

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

Итак, чтобы получить входной путь файла, вы можете сделать следующее:

 Path filePath = ((FileSplit) context.getInputSplit()).getPath(); String filePathString = ((FileSplit) context.getInputSplit()).getPath().toString(); 

Аналогично, чтобы получить имя файла, вы можете просто вызвать getName (), например:

 String fileName = ((FileSplit) context.getInputSplit()).getPath().getName(); 

Используйте это внутри своего картографа:

 FileSplit fileSplit = (FileSplit)context.getInputSplit(); String filename = fileSplit.getPath().getName(); 

Редактировать :

Попробуйте это, если вы хотите сделать это внутри configure () через старый API :

 String fileName = new String(); public void configure(JobConf job) { filename = job.get("map.input.file"); } 

Если вы используете streamи Hadoop Streaming , вы можете использовать переменные JobConf в Mapper / редукторе streamовой работы.

Что касается имени входного файла mapper, см. Раздел « Конфигурируемые параметры », переменная map.input.file ( имя файла, с которой карта считывает ), это то, что можно выполнить map.input.file . Но учтите, что:

Примечание. Во время выполнения streamового задания имена «отображенных» параметров преобразуются. Точки (.) Становятся символами подчеркивания (_). Например, mapred.job.id становится mapred_job_id, а mapred.jar становится mapred_jar. Для получения значений в преобразователе / ​​редукторе задания streamовой передачи используйте имена параметров с символами подчеркивания.


Например, если вы используете Python, вы можете поместить эту строку в файл mapper:

 import os file_name = os.getenv('map_input_file') print file_name 

Заметил на Hadoop 2.4 и выше, используя старый api, этот метод дает нулевое значение

 String fileName = new String(); public void configure(JobConf job) { fileName = job.get("map.input.file"); } 

В качестве альтернативы вы можете использовать объект Reporter, переданный вашей функции карты, чтобы получить InputSplit и передать в FileSplit для получения имени файла

 public void map(LongWritable offset, Text record, OutputCollector out, Reporter rptr) throws IOException { FileSplit fsplit = (FileSplit) rptr.getInputSplit(); String inputFileName = fsplit.getPath().getName(); .... } 

Если вы используете обычный InputFormat, используйте его в своем Mapper:

 InputSplit is = context.getInputSplit(); Method method = is.getClass().getMethod("getInputSplit"); method.setAccessible(true); FileSplit fileSplit = (FileSplit) method.invoke(is); String currentFileName = fileSplit.getPath().getName() 

Если вы используете CombineFileInputFormat, это другой подход, потому что он объединяет несколько небольших файлов в один относительно большой файл (зависит от вашей конфигурации). Оба Mapper и RecordReader работают на одной JVM, поэтому вы можете передавать данные между ними при запуске. Вам необходимо реализовать собственный CombineFileRecordReaderWrapper и сделать следующее:

 public class MyCombineFileRecordReaderWrapper extends RecordReader{ ... private static String mCurrentFilePath; ... public void initialize(InputSplit combineSplit , TaskAttemptContext context) throws IOException, InterruptedException { assert this.fileSplitIsValid(context); mCurrentFilePath = mFileSplit.getPath().toString(); this.mDelegate.initialize(this.mFileSplit, context); } ... public static String getCurrentFilePath() { return mCurrentFilePath; } ... 

Затем в вашем Mapper используйте это:

 String currentFileName = MyCombineFileRecordReaderWrapper.getCurrentFilePath() 

Надеюсь, я помог 🙂

Это помогло мне:

 String fileName = ((org.apache.hadoop.mapreduce.lib.input.FileSplit) context.getInputSplit()).getPath().getName(); 

Вы должны сначала преобразовать в InputSplit методом typecasting, а затем вам нужно ввести cast в FileSplit.

Пример:

 InputSplit inputSplit= (InputSplit)context.getInputSplit(); Path filePath = ((FileSplit) inputSplit).getPath(); String filePathString = ((FileSplit) context.getInputSplit()).getPath().toString() 

Ответы, которые FileSplit от использования FileSplit больше не будут работать, поскольку экземпляры FileSplit больше не возвращаются для нескольких входов (так что вы получите ClassCastException ). Вместо этого возвращаются экземпляры org.apache.hadoop.mapreduce.lib.input.TaggedInputSplit . К сожалению, class TaggedInputSplit недоступен без использования рефлексии. Итак, вот class утилиты, который я написал для этого. Просто делать:

 Path path = MapperUtils.getPath(context.getInputSplit()); 

в вашем Mapper.setup(Context context) .

Вот исходный код для моего classа MapperUtils :

 import org.apache.hadoop.fs.Path; import org.apache.hadoop.mapreduce.InputSplit; import org.apache.hadoop.mapreduce.lib.input.FileSplit; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.reflect.Method; import java.util.Optional; public class MapperUtils { public static Path getPath(InputSplit split) { return getFileSplit(split).map(FileSplit::getPath).orElseThrow(() -> new AssertionError("cannot find path from split " + split.getClass())); } public static Optional getFileSplit(InputSplit split) { if (split instanceof FileSplit) { return Optional.of((FileSplit)split); } else if (TaggedInputSplit.clazz.isInstance(split)) { return getFileSplit(TaggedInputSplit.getInputSplit(split)); } else { return Optional.empty(); } } private static final class TaggedInputSplit { private static final Class clazz; private static final MethodHandle method; static { try { clazz = Class.forName("org.apache.hadoop.mapreduce.lib.input.TaggedInputSplit"); Method m = clazz.getDeclaredMethod("getInputSplit"); m.setAccessible(true); method = MethodHandles.lookup().unreflect(m).asType( MethodType.methodType(InputSplit.class, InputSplit.class)); } catch (ReflectiveOperationException e) { throw new AssertionError(e); } } static InputSplit getInputSplit(InputSplit o) { try { return (InputSplit) method.invokeExact(o); } catch (Throwable e) { throw new AssertionError(e); } } } private MapperUtils() { } } 

Для пакета org.apache.hadood.mapred подпись функции карты должна быть:

 map(Object, Object, OutputCollector, Reporter) 

Итак, чтобы получить имя файла внутри функции map, вы можете использовать объект Reporter следующим образом:

 String fileName = ((FileSplit) reporter.getInputSplit()).getPath().getName(); 
 package com.foo.bar; import org.apache.hadoop.fs.Path; import org.apache.hadoop.mapreduce.InputSplit; import org.apache.hadoop.mapreduce.lib.input.FileSplit; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.reflect.Method; public class MapperUtils { public static Path getPath(InputSplit split) { FileSplit fileSplit = getFileSplit(split); if (fileSplit == null) { throw new AssertionError("cannot find path from split " + split.getClass()); } else { return fileSplit.getPath(); } } public static FileSplit getFileSplit(InputSplit split) { if (split instanceof FileSplit) { return (FileSplit)split; } else if (TaggedInputSplit.clazz.isInstance(split)) { return getFileSplit(TaggedInputSplit.getInputSplit(split)); } else { return null; } } private static final class TaggedInputSplit { private static final Class clazz; private static final MethodHandle method; static { try { clazz = Class.forName("org.apache.hadoop.mapreduce.lib.input.TaggedInputSplit"); Method m = clazz.getDeclaredMethod("getInputSplit"); m.setAccessible(true); method = MethodHandles.lookup().unreflect(m).asType( MethodType.methodType(InputSplit.class, InputSplit.class)); } catch (ReflectiveOperationException e) { throw new AssertionError(e); } } static InputSplit getInputSplit(InputSplit o) { try { return (InputSplit) method.invokeExact(o); } catch (Throwable e) { throw new AssertionError(e); } } } private MapperUtils() { } } 

Я переписываю код hans-brende, предоставляемый на Java 7, он работал. Но есть проблема, которая

Счетчики формата входного файла. Bytes Read = 0 Bytes Read is zero при использовании MultipleInputs.

  • Найти все дубликаты документов в коллекции MongoDB по ключевому полю
  • Размер разделения входов Hadoop и размер блока
  • Как Hadoop выполняет входные расщепления?
  • размер блока данных в HDFS, почему 64 МБ?
  • Единовременный эквивалент сохраненной процедуры MongoDB
  • объединить выходные файлы после фазы уменьшения
  • Объединение нескольких заданий MapReduce в Hadoop
  • Hadoop DistributedCache устарел - какой предпочтительный API?
  • Объединение двух коллекций в MongoDB
  • Установка количества задач карты и сокращение задач
  • Какова цель фаз перетасовки и сортировки в редукторе в Программе сокращения карты?
  • Давайте будем гением компьютера.