복붙노트

[HADOOP] 값을 두 번 반복 (MapReduce)

HADOOP

값을 두 번 반복 (MapReduce)

인수로서 반복자를 받고 값을 두 번 반복하고 싶습니다.

public void reduce(Pair<String,String> key, Iterator<IntWritable> values,
                   Context context)

가능한가? 어떻게? 서명은 내가 사용하고있는 프레임 워크 (즉, Hadoop)에 의해 부과됩니다.

-- 편집하다 -- 마지막으로 reduce 메소드의 실제 서명은 반복 가능합니다. 나는이 위키 페이지 (실제로는 내가 찾은 단어 수의 유일한 비 - 비추천 (그러나 잘못된) 예이다)에 속아 넘어졌다.

해결법

  1. ==============================

    1.다시 반복하려는 경우 반복기에서 값을 캐시해야합니다. 적어도 우리는 첫 번째 반복과 캐싱을 결합 할 수 있습니다.

    다시 반복하려는 경우 반복기에서 값을 캐시해야합니다. 적어도 우리는 첫 번째 반복과 캐싱을 결합 할 수 있습니다.

    Iterator<IntWritable> it = getIterator();
    List<IntWritable> cache = new ArrayList<IntWritable>();
    
    // first loop and caching
    while (it.hasNext()) {
       IntWritable value = it.next();
       doSomethingWithValue();
       cache.add(value);
    }
    
    // second loop
    for(IntWritable value:cache) {
       doSomethingElseThatCantBeDoneInFirstLoop(value);
    }
    

    (코드에 대한 답을 추가하기 위해서, 당신이 당신의 코멘트에이 솔루션을 언급했다는 것을 알고 있어야합니다.))

    캐싱 없이는 불가능한 이유는 무엇입니까? Iterator는 인터페이스를 구현하고 Iterator 객체가 실제로 값을 저장한다는 단일 요구 사항이 아닙니다. 두 번 반복하면 반복자를 재설정하거나 (복제 할 수 없음) 다시 복제해야합니다.

    복제 / 재설정이 의미가없는 반복자에 대한 예제를 제공하려면 다음을 수행하십시오.

    public class Randoms implements Iterator<Double> {
    
      private int counter = 10;
    
      @Override 
      public boolean hasNext() { 
         return counter > 0; 
      }
    
      @Override 
      public boolean next() { 
         count--;
         return Math.random();        
      }      
    
      @Override 
      public boolean remove() { 
         throw new UnsupportedOperationException("delete not supported"); 
      }
    }
    
  2. ==============================

    2.안타깝게도 Andreas_D의 대답처럼 값을 캐싱하지 않으면이 작업을 수행 할 수 없습니다.

    안타깝게도 Andreas_D의 대답처럼 값을 캐싱하지 않으면이 작업을 수행 할 수 없습니다.

    Reducer가 Iterator가 아닌 Iterable을받는 새 API를 사용하더라도 두 번 반복 할 수 없습니다. 다음과 같은 것을 시도하는 것은 매우 유혹적입니다.

    for (IntWritable value : values) {
        // first loop
    }
    
    for (IntWritable value : values) {
        // second loop
    }
    

    하지만 실제로는 작동하지 않습니다. 그 Iterable의 iterator () 메소드로부터받는 Iterator는 특별하다. 값이 모두 메모리에 있지 않을 수도 있습니다. Hadoop이 디스크에서 스트리밍 중일 수 있습니다. 컬렉션에 의해 뒷받침되지는 않으므로 여러 번 반복 할 수 있습니다.

    Reducer 및 ReduceContext 코드에서 직접 확인할 수 있습니다.

    콜렉션에서 값을 일종의 캐시로 저장하는 것이 가장 쉬운 방법 일 수 있지만 대용량 데이터 세트에서 작업하는 경우에는 힙을 쉽게 날려 버릴 수 있습니다. 문제에 대해 더 자세한 정보를 제공 할 수 있다면 여러 번의 반복을 필요로하지 않는 솔루션을 찾을 수 있습니다.

  3. ==============================

    3.지정된 반복자를 다시 사용합니다.

    지정된 반복자를 다시 사용합니다.

    하지만 ArrayList의 값을 처음부터 반복 한 다음 생성 된 ArrayList를 반복 할 때 ArrayList에 값을 저장할 수 있습니다. (또는 멋진 컬렉션 메서드를 사용하여 직접 빌드 한 다음 해당 컬렉션에 직접 반복 할 수 있습니다. ArrayList 두 번, 그것은 맛의 문제입니다).

    어쨌든, 반복자를 전달하는 것이 처음부터 좋은 일인 지 확실합니까? 반복자는 컬렉션을 통해 선형 스캔을 수행하는 데 사용되므로 이러한 방식으로 "되감기"메소드가 노출되지 않습니다.

    이미 다른 답변에서 제안 된 Collection 또는 Iterable 와 같이 다른 것을 전달해야합니다.

  4. ==============================

    4.반복자는 하나의 순회 전용입니다. 일부 반복자 유형은 복제 가능하므로 탐색하기 전에 복제 할 수는 있지만 일반적으로 발생하는 것은 아닙니다.

    반복자는 하나의 순회 전용입니다. 일부 반복자 유형은 복제 가능하므로 탐색하기 전에 복제 할 수는 있지만 일반적으로 발생하는 것은 아닙니다.

    당신이 그것을 달성 할 수 있다면, 대신에 당신의 함수가 반복 가능하도록 만들어야한다.

  5. ==============================

    5.메서드 서명을 변경할 수 없다면 Apache Commons IteratorUtils를 사용하여 Iterator를 ListIterator로 변환하는 것이 좋습니다. 값을 두 번 반복하는 다음 예제 메서드를 고려하십시오.

    메서드 서명을 변경할 수 없다면 Apache Commons IteratorUtils를 사용하여 Iterator를 ListIterator로 변환하는 것이 좋습니다. 값을 두 번 반복하는 다음 예제 메서드를 고려하십시오.

    void iterateTwice(Iterator<String> it) {
        ListIterator<?> lit = IteratorUtils.toListIterator(it);
        System.out.println("Using ListIterator 1st pass");
        while(lit.hasNext())
            System.out.println(lit.next());
    
        // move the list iterator back to start
        while(lit.hasPrevious())
            lit.previous();
    
        System.out.println("Using ListIterator 2nd pass");
        while(lit.hasNext())
            System.out.println(lit.next());
    }
    

    위의 코드를 사용하면 코드에서 List 요소의 복사본을 저장하지 않고도 값 목록을 반복 할 수있었습니다.

  6. ==============================

    6.Reducer에서 아래와 같이 두 번 반복하려는 경우

    Reducer에서 아래와 같이 두 번 반복하려는 경우

    ListIterator<DoubleWritable> lit = IteratorUtils.toListIterator(it);
    System.out.println("Using ListIterator 1st pass");
    while(lit.hasNext())
        System.out.println(lit.next());
    
    // move the list iterator back to start
    while(lit.hasPrevious())
        lit.previous();
    
    System.out.println("Using ListIterator 2nd pass");
    while(lit.hasNext())
        System.out.println(lit.next());
    

    우리는 다음과 같이 출력 할 것입니다.

    Using ListIterator 1st pass
    5.3
    4.9
    5.3
    4.6
    4.6
    Using ListIterator 2nd pass
    5.3
    5.3
    5.3
    5.3
    5.3
    

    Inorder를 올바른 방법으로 얻으려면 다음과 같이 반복해야합니다.

    ArrayList<DoubleWritable> cache = new ArrayList<DoubleWritable>();
     for (DoubleWritable aNum : values) {
        System.out.println("first iteration: " + aNum);
        DoubleWritable writable = new DoubleWritable();
        writable.set(aNum.get());
        cache.add(writable);
     }
     int size = cache.size();
     for (int i = 0; i < size; ++i) {
         System.out.println("second iteration: " + cache.get(i));
      }
    

    산출

    first iteration: 5.3
    first iteration: 4.9
    first iteration: 5.3
    first iteration: 4.6
    first iteration: 4.6
    second iteration: 5.3
    second iteration: 4.9
    second iteration: 5.3
    second iteration: 4.6
    second iteration: 4.6
    
  7. ==============================

    7.너는 그걸 할 수있어.

    너는 그걸 할 수있어.

    MarkableIterator<Text> mitr = new MarkableIterator<Text>(values.iterator());
    mitr.mark();
    while (mitr.hasNext()) 
    {
    //do your work
    }
    mitr.reset();
    while(mitr.hasNext()) 
    {
    //again do your work
    }
    
  8. ==============================

    8.이 시도:

    이 시도:

        ListIterator it = list.listIterator();
    
        while(it.hasNext()){
    
            while(it.hasNext()){
                System.out.println("back " + it.next() +" "); 
            }
            while(it.hasPrevious()){
                it.previous();
            }
        }
    
  9. ==============================

    9.값을 변경하려면 listIterator를 사용하고 set () 메서드를 사용하는 것이 좋습니다.

    값을 변경하려면 listIterator를 사용하고 set () 메서드를 사용하는 것이 좋습니다.

    ListIterator lit = list.listIterator();
    while(lit.hasNext()){
       String elem = (String) lit.next();
       System.out.println(elem);
       lit.set(elem+" modified");
    }
    lit = null; 
    lit = list.listIterator();
    while(lit.hasNext()){
       System.out.println(lit.next());
    }
    

    .previous ()를 호출하는 대신, 같은 list iterator 객체에서 .listIterator ()의 또 다른 인스턴스를 얻는다.

  10. ==============================

    10.검색과 많은 시도와 오류를 한 후에 해결책을 찾았습니다.

    검색과 많은 시도와 오류를 한 후에 해결책을 찾았습니다.

  11. from https://stackoverflow.com/questions/6111248/iterate-twice-on-values-mapreduce by cc-by-sa and MIT license