Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/358.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 是什么决定了减速器的数量以及如何避免减速器的瓶颈?_Java_Hadoop_Mapreduce - Fatal编程技术网

Java 是什么决定了减速器的数量以及如何避免减速器的瓶颈?

Java 是什么决定了减速器的数量以及如何避免减速器的瓶颈?,java,hadoop,mapreduce,Java,Hadoop,Mapreduce,假设我有一个包含此类信息的大tsv文件: 2012-09-22 00:00:01.0 249342258346881024 47268866 0 0 0 bo 2012-09-22 00:00:02.0 249342260934746115 1344951 0 0 4 ot 2012-09-22 00:00:02.0 249342261098336257 346095334 1 0 0 ot 2012-09-22 00:05

假设我有一个包含此类信息的大tsv文件:

2012-09-22 00:00:01.0   249342258346881024  47268866    0   0   0   bo
2012-09-22 00:00:02.0   249342260934746115  1344951     0   0   4   ot
2012-09-22 00:00:02.0   249342261098336257  346095334   1   0   0   ot
2012-09-22 00:05:02.0   249342261500977152  254785340   0   1   0   ot
我想实现一个MapReduce作业,它枚举五分钟的时间间隔并过滤tsv输入的一些信息。输出文件如下所示:

0 47268866  bo
0 134495    ot
0 346095334 ot
1 254785340 ot
键是间隔的编号,例如,0是
2012-09-22 00:00:00.0
2012-09-22 00:04:59
之间间隔的参考

我不知道这个问题是否适合MapReduce方法,或者我是否认为它不正确。在map函数中,我只是将时间戳作为键传递,将过滤后的信息作为值传递。在reduce函数中,我使用全局变量计算时间间隔,并生成上面提到的输出

i.框架是自动确定减速机的数量,还是由用户定义?使用一个reducer,我认为我的方法没有问题,但我想知道,在处理真正大的文件时,一个reduce是否会成为瓶颈,是吗

ii.如何解决多个减速器的问题

任何建议都将不胜感激! 提前谢谢

编辑:

第一个问题由@Olaf回答,但第二个问题仍然让我对并行性产生了一些疑问。我的map函数的map输出目前如下(我只是以分钟精度传递时间戳):

因此,在reduce函数中,我接收到输入,键表示收集信息时的分钟数,值表示信息本身,我想枚举从0开始的五分钟间隔。我目前正在使用一个全局变量来存储间隔的开始,当一个键外推它时,我将递增间隔计数器(这也是一个全局变量)

代码如下:

private long stepRange = TimeUnit.MINUTES.toMillis(5);
private long stepInitialMillis = 0;
private int stepCounter = 0;

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

    long millis = Long.valueOf(key.toString());
    if (stepInitialMillis == 0) {
        stepInitialMillis = millis;
    } else {
        if (millis - stepInitialMillis > stepRange) {
            stepCounter = stepCounter + 1;
            stepInitialMillis = millis;
        }
    }
    for (Text value : values) {
        context.write(new Text(String.valueOf(stepCounter)),
                new Text(key.toString() + "\t" + value));
    }
}
private long stepRange=时间单位.MINUTES.toMillis(5);
私有长步长初始值毫秒=0;
私有整数步计数器=0;
@凌驾
公共void reduce(文本键、Iterable值、上下文)
抛出IOException、InterruptedException{
long millis=long.valueOf(key.toString());
如果(stepInitialMillis==0){
StepInitialis=millis;
}否则{
如果(毫秒-步长初始值毫秒>步长范围){
步进计数器=步进计数器+1;
StepInitialis=millis;
}
}
用于(文本值:值){
context.write(新文本(String.valueOf(stepCounter)),
新文本(key.toString()+“\t”+值);
}
}

因此,有了多个reducer,我的reduce函数将在两个或多个JVM中的两个或多个节点上运行,我将失去全局变量提供的控制,并且我不考虑解决我的问题。

reducer的数量取决于集群的配置,尽管您可以限制MapReduce作业使用的还原器的数量

如果您处理的数据量很大,那么单个reducer确实会成为MapReduce工作的瓶颈

Hadoop MapReduce引擎保证与同一个键关联的所有值都被发送到同一个减缩器,因此您的方法应该使用多重减缩器。看看雅虎!有关详细信息,请参阅教程:

编辑:为了保证同一时间间隔的所有值都归同一个减速机,必须使用该时间间隔的某个唯一标识符作为键。你必须在地图绘制程序中完成。我再次阅读了您的问题,除非您想以某种方式聚合对应于相同时间间隔的记录之间的数据,否则根本不需要任何缩减器


编辑:正如@SeanOwen指出的,减速器的数量取决于集群的配置。通常,它的配置为每个节点的最大任务数乘以数据节点数的0.95到1.75倍。如果未在群集配置中设置mapred.reduce.tasks值,则默认的reducer数为1。

看起来您希望按5分钟的数据块聚合一些数据。使用Hadoop的Map reduce非常适合这种情况!没有理由使用任何“全局变量”。以下是我将如何设置它:

映射器读取TSV的一行。它获取时间戳,并计算它属于哪个5分钟的存储桶。将其转换为字符串,并将其作为键发出,如“20120922:0000”、“20120922:0005”、“20120922:0010”等。至于随该键发出的值,只需保持简单即可,并将整个制表符分隔行作为另一个文本对象发送

既然映射器已经确定了数据需要如何组织,那么还原器的工作就是进行聚合。每个减速机都会有一把钥匙(五分钟铲斗中的一把),以及适合该铲斗的所有管路的列表。它可以迭代该列表,并从中提取它想要的任何内容,根据需要将输出写入上下文

至于映射程序,就让hadoop来解决这个问题吧。将减少器的数量设置为集群中的节点数,作为起点。应该跑得很好


希望这有帮助。

谢谢您的快速回答!关于第二个问题,我编辑了我的帖子以更好地解释我的问题。@JoãoMelo:我再次阅读了你的问题并编辑了我的答案。您想要的功能最好在映射器中实现。我同意您的观点,但在我的方法中,间隔计数器从文件的第一个时间戳开始,在本例中是第一个块的第一个时间戳。我想这是不可能的,因为每个节点将使用不同的块和不同的全局变量运行一个实例,对吗?@JoãoMelo:我相信你的评估是正确的。如果不读取整个文件集合,就无法找到最早的时间戳。你能用一些绝对值吗
private long stepRange = TimeUnit.MINUTES.toMillis(5);
private long stepInitialMillis = 0;
private int stepCounter = 0;

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

    long millis = Long.valueOf(key.toString());
    if (stepInitialMillis == 0) {
        stepInitialMillis = millis;
    } else {
        if (millis - stepInitialMillis > stepRange) {
            stepCounter = stepCounter + 1;
            stepInitialMillis = millis;
        }
    }
    for (Text value : values) {
        context.write(new Text(String.valueOf(stepCounter)),
                new Text(key.toString() + "\t" + value));
    }
}