2012-11-17 32 views
0

我正在編寫Hadoop應用程序,但似乎我誤解了hadoop的工作原理。我的輸入文件是根據QuadTile原則命名的地圖。我需要對這些樣本進行二次抽樣,然後將這些樣本拼接在一起,直到我擁有一個覆蓋面積較大但分辨率較低的較高層次的拼貼。就像縮小在谷歌地圖。Hadoop數據和控制流程

一個我做的事情是,我已經寫了,其執行上的每個(unsplittable)瓷磚這樣的映射:

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)當沒有更多的地圖離開 - >寫輸出

原來,這是不正確的。我的reducer在每個Map之後被調用,並且Iterable似乎不會有多個元素。我試圖通過假設Iterable會有2個元素來改變Reducer代碼來解決這個問題:一個子採樣值和一個部分完成的高級tile。原來,這也是不正確的。

有誰能告訴我,或者指向我,hadoop的流程究竟是怎樣的?我應該怎樣做我的用例工作?我希望我解釋清楚。

回答

3

你的假設是正確的,所有的地圖在第一次減少開始之前完成。這是因爲每個reduce都會保證以排序順序得到輸入,並且最後一個要完成的地圖可能會爲所有縮減生成第一個鍵。

每個映射產生它的輸出,一個稱爲分區器的可插入接口選擇應該接收每個密鑰的reduce。默認情況下使用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

+0

你說所有地圖在第一次減少開始之前完成。但在我當前的代碼中,這是在單節點模式下運行的,他們真的不會......在輸入文件被完全映射後執行reduce是否可能?由於我的tile不可解析,所以每次map任務後都會發生第一次reduce。感謝您的回答。 – KarelV

+0

啊,我看到在我的驅動程序代碼中combinerclass被設置爲我的reducer,可能是一些複製的代碼,我完全忘了。我註釋到了代碼,現在只在所有映射完成後才發生縮減。現在我需要迭代地圖並減少操作,直到只剩下某個鍵,這應該是要求的拼貼。我將爲此啓動一個新問題。感謝您的回答。 – KarelV