Данные Hadoop и поток управления

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

Одна из вещей, которые я сделал, это то, что я написал маппер, который выполняется на каждом (неразделяемом) тайле следующим образом:

public void map(Text keyT, ImageWritable value, Context context) throws IOException, InterruptedException {

     String key = keyT.toString();

    //check whether file needs to be processed
     if(key.startsWith(context.getJobName(), 0)){

         String newKey = key.substring(0, key.length()-1);
         ImageWritable iw = subSample(value);
         char region = key.charAt(key.length()-1);
         iw.setRegion(region);
         context.write(new Text(newKey), iw);
     }else{
         //tile not needed in calculation
     }
 }

Мой редуктор выглядит так:

public void reduce(Text key, Iterable<ImageWritable> values, Context context) throws IOException, InterruptedException{

    ImageWritable higherLevelTile = new ImageWritable();
    int i = 0;
    for(ImageWritable s : values){
        int width = s.getWidth();
        int height = s.getHeight();
        char c = Character.toUpperCase(s.getRegion());
        int basex=0, basey=0;
        if(c=='A'){
            basex = basey = 0;
        }else if(c=='B'){
            basex = width;
            basey = 0;
        }else if(c=='C'){
            basex = 0;
            basey = height;             
        }else{
            basex = width;
            basey = height;
        }

        BufferedImage toDraw = s.getBufferedImage();
        Graphics g = higherLevelTile.getBufferedImage().getGraphics();
        g.drawImage(toDraw, basex, basey, null);
    }               
    context.write(key, higherLevelTile);

}

Как вы, возможно, можете извлечь из моего кода, я ожидал, что hadoop будет выполняться следующим образом: 1) Сопоставьте все плитки первого уровня 2) Выполните первое сокращение. здесь я ожидал, что значения Iterable будут иметь четыре элемента: четыре субдискретизированных плитки нижнего уровня. 3) Отобразить все плитки в настоящее время в контексте 4) уменьшить все плитки в контексте. Опять же, значения Iterable будут иметь 4 элемента... 5) ... повторить... 6) когда больше не останется карт -> запись вывода

Оказывается, это не правильно. Мой редьюсер вызывается после каждой карты, и у Iterable никогда не бывает более одного элемента. Я попытался исправить это, немного изменив код редуктора, предполагая, что Iterable будет иметь 2 элемента: одно субдискретизированное значение и один частично законченный тайл более высокого уровня. Оказывается, это тоже не правильно.

Может ли кто-нибудь сказать мне или указать мне, как на самом деле работает поток хаупов? Что я должен сделать, чтобы мой вариант использования работал? Надеюсь понятно объяснил.


person KarelV    schedule 17.11.2012    source источник


Ответы (1)


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

Каждая карта производит свой вывод, подключаемый интерфейс, называемый разделителем, выбирает сокращение, которое должно получить каждый ключ. По умолчанию используется key.hashCode() % num_reduces, потому что в обычном случае это дает хорошее распределение. Это может быть вашей проблемой, поскольку нет требований, чтобы "A", "AB" и "ABC" пошли на одно и то же сокращение.

Наконец, каждое из сокращений вызывается один раз для каждого из его ключей. Итератор перебирает значения, связанные с одним и тем же ключом. Обратите внимание, что значения обычно не сортируются, но это можно контролировать с помощью вторичной сортировки.

Взгляните на: http://riccomini.name/posts/hadoop/2009-11-13-sort-reducer-input-value-hadoop/ .

Если вам нужен пример вторичной сортировки, я написал его и поместил в примеры Hadoop. http://svn.apache.org/repos/asf/hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-examples/src/main/java/org/apache/hadoop/examples/SecondarySort.java

person user1832092    schedule 17.11.2012
comment
Вы говорите, что все карты заканчиваются до того, как начнется первая редукция. Но в моем текущем коде, который работает в режиме одного узла, они действительно не работают... Может ли быть, что сокращение выполняется после того, как входной файл полностью сопоставлен? Поскольку мои плитки неразделимы, первое уменьшение будет происходить после каждой задачи карты? Спасибо за Ваш ответ. - person KarelV; 18.11.2012
comment
А, я вижу, что в коде моего драйвера для класса Combiner был установлен мой редуктор, вероятно, какой-то скопированный код, о котором я совершенно забыл. Я закомментировал этот код, и теперь сокращение происходит только после завершения всех карт. Прямо сейчас мне нужно перебрать карту и сократить количество операций до тех пор, пока не останется только определенный ключ, который должен быть запрошенной плиткой. Я начну новый вопрос для этого. Спасибо за Ваш ответ. - person KarelV; 18.11.2012