Hadoop数据和控制流
我正在编写一个Hadoop应用程序,但我似乎误解了Hadoop的工作原理。我的输入文件是地图的分片,根据原则命名。我需要对它们进行二次采样,然后将它们缝合在一起,直到我得到一个覆盖更大区域但分辨率更低的更高级别的瓷砖。比如在谷歌地图中缩小 我所做的一件事是,我编写了一个映射程序,它在每个(不可拆分的)分片上执行,如下所示:Hadoop数据和控制流,hadoop,mapreduce,control-flow,dataflow,Hadoop,Mapreduce,Control Flow,Dataflow,我正在编写一个Hadoop应用程序,但我似乎误解了Hadoop的工作原理。我的输入文件是地图的分片,根据原则命名。我需要对它们进行二次采样,然后将它们缝合在一起,直到我得到一个覆盖更大区域但分辨率更低的更高级别的瓷砖。比如在谷歌地图中缩小 我所做的一件事是,我编写了一个映射程序,它在每个(不可拆分的)分片上执行,如下所示: public void map(Text keyT, ImageWritable value, Context context) throws IOException, In
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);
}
我的减速机是这样的:
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);
}
public void reduce(文本键、Iterable值、上下文)抛出IOException、InterruptedException{
ImageWritable HigherLevel=新的ImageWritable();
int i=0;
for(可写入图像:值){
int width=s.getWidth();
int height=s.getHeight();
char c=Character.toUpperCase(s.getRegion());
int basex=0,basey=0;
如果(c=='A'){
basex=basey=0;
}else如果(c=='B'){
basex=宽度;
basey=0;
}else如果(c=='c'){
basex=0;
basey=高度;
}否则{
basex=宽度;
basey=高度;
}
BuffereImage toDraw=s.GetBuffereImage();
Graphics g=HigherLevel.GetBuffereImage().getGraphics();
g、 drawImage(toDraw、basex、basey、null);
}
编写(键,高级平铺);
}
正如您可能从我的代码中得到的一样,我希望hadoop以以下方式执行:
1) 映射一级的所有分幅
2) 先做一个减量。在这里,我期望Iterable值包含四个元素:较低级别的四个子采样图块。
3) 映射当前上下文中的所有分幅
4) 减少上下文中的所有平铺。同样,Iterable值将有4个元素。。。
5) ... 重复。。。
6) 当没有更多贴图时->写入输出
事实证明,这是不对的。我的reducer在每个Map之后都被调用,而Iterable似乎从来没有超过一个元素。我试图通过稍微修改reducer代码来解决这个问题,假设Iterable有两个元素:一个是子采样值,另一个是部分完成的更高级别的tile。事实证明,这也不正确
有人能告诉我,或者告诉我hadoop的流程是怎样的吗?我应该怎么做才能使我的用例工作?我希望我解释得很清楚。您的假设是正确的,所有地图都在第一次还原开始之前完成。这是因为每个reduce都保证按排序顺序获取其输入,最后一个要完成的映射可能会为所有reduce生成第一个键 每个映射生成其输出,一个称为分区器的可插入接口选择应该接收每个键的reduce。默认使用
key.hashCode()%num\u减少
,因为这在正常情况下提供了良好的分布。这可能是您的问题,因为没有要求“A”
,“AB”
,“ABC”
将转到同一个reduce
最后,每个reduce对其每个键调用一次。迭代器遍历与同一个键关联的值。请注意,这些值通常是未排序的,但可以通过二级排序进行控制
请看:
如果你想要一个二级排序的例子,我写了一个并把它放在Hadoop例子中 您的假设是正确的,所有贴图都在第一次reduce开始之前完成。这是因为每个reduce都保证按排序顺序获取其输入,最后一个要完成的映射可能会为所有reduce生成第一个键 每个映射生成其输出,一个称为分区器的可插入接口选择应该接收每个键的reduce。默认使用
key.hashCode()%num\u减少
,因为这在正常情况下提供了良好的分布。这可能是您的问题,因为没有要求“A”
,“AB”
,“ABC”
将转到同一个reduce
最后,每个reduce对其每个键调用一次。迭代器遍历与同一个键关联的值。请注意,这些值通常是未排序的,但可以通过二级排序进行控制
请看:
如果你想要一个二级排序的例子,我写了一个并把它放在Hadoop例子中 您说所有贴图在第一个reduce开始之前完成。但在我当前的代码中,它是在单节点模式下运行的,它们实际上不。。。是否在输入文件完全映射后执行reduce?由于我的分片无法丢弃,每次地图任务后都会出现第一次减少?谢谢你的回答。啊,我在我的驱动程序代码中看到combinerclass被设置为我的reducer,可能是一些我完全忘记的复制代码。我注释掉了那段代码,现在只有在所有映射完成后才会出现reduce。现在我需要迭代映射并减少操作,直到只剩下某个键,该键应该是所请求的磁贴。我将为此提出一个新问题。谢谢你的回答。你说所有的地图在第一次还原开始之前就完成了。但在我当前的代码中,它是在单节点模式下运行的,它们实际上不。。。是否在输入文件完全映射后执行reduce?由于我的分片无法丢弃,每次地图任务后都会出现第一次减少?谢谢你的回答。啊,我在我的驱动程序代码中看到combinerclass被设置为我的reducer,可能是一些我完全忘记的复制代码。我注释掉了那段代码,现在只有在所有映射完成后才会出现reduce。现在我需要迭代映射并减少操作,直到只剩下某个键,该键应该是所请求的磁贴。我将为此提出一个新问题。谢谢你的回答。