Есть ли способ получить доступ к количеству успешных задач карты из задачи сокращения в задании MR?

#hadoop #mapreduce

#hadoop #mapreduce

Вопрос:

В моих редукторах Hadoop мне нужно знать, сколько успешных задач карты было выполнено в текущем задании. Я придумал следующее, которое, насколько я могу судить, НЕ работает.

     Counter totalMapsCounter = 
        context.getCounter(JobInProgress.Counter.TOTAL_LAUNCHED_MAPS);
    Counter failedMapsCounter = 
        context.getCounter(JobInProgress.Counter.NUM_FAILED_MAPS);
    long nSuccessfulMaps = totalMapsCounter.getValue() - 
                           failedMapsCounter.getValue();
  

В качестве альтернативы, если есть хороший способ, которым я мог бы получить (опять же, из моих редукторов) общее количество входных разбиений (не количество файлов и не разбиения для одного файла, а общее количество разбиений для задания), это, вероятно, также сработало бы. (Предполагая, что моя работа завершается нормально, это должно быть то же самое число, верно?)

Комментарии:

1. Чем больше я думаю об этом, тем больше я думаю, что моя проблема на самом деле связана с объемом счетчиков. Я могу увеличивать и считывать счетчик просто отлично в пределах одного картографа или редуктора, но что мне нужно / хотеть, так это способ считывания глобально агрегированного значения счетчика (вычисляемого в моих картографах и используемого в моих редукторах).

Ответ №1:

Редактировать: Похоже, что не рекомендуется извлекать счетчики на карте и сокращать задачи с помощью Job или JobConf. Вот <a rel="noreferrer noopener nofollow" href="https:///mail-archives.apache.org/mod_mbox/hadoop-mapreduce-user/201112.mbox/» rel=»nofollow»>альтернативный подход для передачи сводных сведений из mapper в reducer. Этот подход требует некоторых усилий для кодирования, но выполним. Было бы неплохо, если бы функция была частью Hadoop и не требовала ее ручного кодирования. Я запросил поместить эту функцию в Hadoop и жду ответа.


Счетчик заданий.TOTAL_LAUNCHED_MAPS был получен с использованием приведенного ниже кода в классе Reducer со старым MR API.

 private String jobID;
private long launchedMaps;

public void configure(JobConf jobConf) {

    try {
        jobID = jobConf.get("mapred.job.id");

        JobClient jobClient = new JobClient(jobConf);

        RunningJob job = jobClient.getJob(JobID.forName(jobID));

        if (job == null) {
            System.out.println("No job with ID found "   jobID);
        } else {
            Counters counters = job.getCounters();
            launchedMaps = counters.getCounter(JobCounter.TOTAL_LAUNCHED_MAPS);
        }

    } catch (Exception e) {
        e.printStackTrace();
    }
}
  

С новым API реализации Reducer могут получить доступ к конфигурации для задания через JobContext#getConfiguration(). Приведенный выше код может быть реализован в Reducer#setup().

Reducer#configure() в старом MR API и Reducer#setup() в новом MR API вызываются один раз для каждой задачи сокращения, прежде чем вызывается Reducer.reduce().

Кстати, счетчики могут быть получены из другой JVM, кроме той, которая запустила задание.

JobInProgress определяется как показано ниже, поэтому его не следует использовать. Этот API предназначен только для ограниченных проектов, и интерфейс может измениться.

@InterfaceAudience.LimitedPrivate({«MapReduce»})
@InterfaceStability.Нестабильно

Не это, JobCounter.TOTAL_LAUNCHED_MAPS также включает задачи карты, запущенные из-за спекулятивного выполнения

Комментарии:

1. Я полагаю, вы только обрисовали в общих чертах мое предлагаемое решение, которое не работает из редуктора. Это сработает, если вы получите доступ к счетчикам из задания в JVM, которое запускает задание, но не думаю, что это сработает из редуктора (я уже пробовал это).

2. Изменен ответ с другим подходом. Позже я нашел аналогичный запрос SO с аналогичным решением.

3. @Thomas — что вы подразумеваете под зависимостью от версии?

4. @PraveenSripati Интересный подход, но не думаю, что это выполнимо в новом API (который я использую). Можно создать экземпляр JobClient только с помощью JobConf, но то, что вы получаете из Context#getConfiguration(), имеет тип Configuration, а не JobConf.

5. @Mark — o.a.h.mapred. JobConf расширяет o.a.h.conf. Конфигурация. Итак, использование простого приведения типов JobConf jobConf = (JobConf) context.getConfiguration(); устранило проблему. Также удалось получить счетчики в новом API. Кстати, между старым и новым API нет большой разницы .

Ответ №2:

Используя новый API, я извлек один пользовательский счетчик (перечисление в Mapper) и встроенный счетчик. Это код моего редуктора: это в методе настройки редуктора. Хотя там мне приходится использовать некоторые классы старого API (пакет mapred)

     JobContext jobContext= new JobContext(context.getConfiguration(), context.getJobID());
    Configuration c= jobContext.getConfiguration();

    jobID=c.get("mapred.job.id");
    //jobId= JobID.forName(jobID);

    JobClient jobClient = new JobClient(new JobConf(c));

    RunningJob job = jobClient.getJob((org.apache.hadoop.mapred.JobID) JobID.forName(jobID));

    Counters counters = job.getCounters();

    long customCounterCount= counters.getCounter(WordCountMapper.CustomCounters.COUNT);

    long totalMapInputRecords = counters.getCounter(Task.Counter.MAP_INPUT_RECORDS);

    System.out.println("customCounterCount==> "   customCounterCount);
    System.out.println("totalMapInputRecords==> "   totalMapInputRecords);