2017-02-19 36 views
0

У меня есть следующий код внутри моей функции сокращения. Когда я пытаюсь сделать мелкую копию с помощью CollectionUtils.addAll, копия не удалась; все элементы будут иметь ссылку на элемент LAST вместо других элементов в итераторе.Итеративное значение Reducer, по-видимому, непоследовательно в Java MapReduce

Вот код из моего Reducer:

public void reduce(Text key, Iterable<ArrayListWritable<Writable>> values, Context context) 
    throws IOException, InterruptedException { 
    ArrayList<ArrayListWritable<Writable>> listOfWordPairs = new ArrayList<ArrayListWritable<Writable>>(); 

    // CollectionUtils.addAll(listOfWordPairs, values.iterator()); 
    // listOfWordPairs seems to all be the last item in the iterator 

    Iterator<ArrayListWritable<Writable>> iter = values.iterator(); 

    // Manually do the copy 
    while (iter.hasNext()) { 
     // listOfWordPairs.add(iter.next()); 
     //Same behaviour as CollectionUtils.addAll() 

     listOfWordPairs.add(new ArrayListWritable<Writable>(iter.next())); 
     //Only working way to do it -> deep copy :(
     } 
    } 

Кто-нибудь есть какие-либо идеи, почему это происходит? Я вижу, что если MR реализовала его таким образом, он может сэкономить довольно большой кусок памяти, но, похоже, здесь происходит какая-то магия, чтобы это произошло. Я новичок в MR так что надеюсь, вопрос не слишком глуп ...

Вот мой MAP код для людей, которые заинтересованы

@Override 
     public void map(LongWritable key, Text value, Context context) 
      throws IOException, InterruptedException { 
      Map<String, HMapStFW> stripes = new HashMap<>(); 

      List<String> tokens = Tokenizer.tokenize(value.toString()); 

      if (tokens.size() < 2) return; 
      context.getCounter(StripesPmiEnums.TOTALENTRIES).increment(tokens.size()); 

      for (int i = 0; i < tokens.size() && i<40; i++) { 
      for (int j = 0;j<tokens.size() && j<40;j++){ 
       if (j == i) 
        continue; 
       //Make Stripe if doesn't exist 
       if (!stripes.containsKey(tokens.get(i))){ 
        HMapStFW newStripe = new HMapStFW(); 
        stripes.put(tokens.get(i), newStripe); 
       } 

       HMapStFW stripe = stripes.get(tokens.get(i)); 
       if (stripe.containsKey(tokens.get(j))){ 
        stripe.put(tokens.get(j), stripe.get(tokens.get(j))+1.0f); 
       }else{ 
        stripe.put(tokens.get(j), 1.0f); 
       } 
      } 
      } 

      for (String word1 : stripes.keySet()) { 
      TEXT.set(word1); 
      context.write(TEXT, stripes.get(word1)); 
      } 
     } 

А также ArrayListWritable доступна здесь https://github.com/lintool/tools/blob/master/lintools-datatypes/src/main/java/tl/lin/data/array/ArrayListWritable.java

+0

Это кажется мне переопределить записываемый вы можете поделиться этим кодом вместе с кодом mapper. –

+0

@siddhartha jain Я добавил его в OP – user3538310

+1

Возможный дубликат [Hadoop MapReduce итерации по входным значениям вызова сокращения] (http://stackoverflow.com/questions/15976981/hadoop-mapreduce-iterate-over-input-values -of-а-снизить-вызов) –

ответ

0

Это потому, что итератор работает в редукторе. Короткий ответ, вы должны клонировать объект в то время как вы итерацию итератора

while (iter.hasNext()) { 
    //this is correct 
    listOfWordPairs.add(new ArrayListWritable<Writable>(iter.next())); 

    } 
} 

взглянуть на следующую ссылку, это очень хорошо объяснен

https://cornercases.wordpress.com/2011/08/18/hadoop-object-reuse-pitfall-all-my-reducer-values-are-the-same/