Hadoop 需要帮助编写地图/减少作业以找到平均值

Hadoop 需要帮助编写地图/减少作业以找到平均值,hadoop,mapreduce,Hadoop,Mapreduce,我是Hadoop Map/Reduce的新手。我正在尝试编写一个Map/Reduce作业,以查找n个进程所花费的平均时间,给定一个输入文本文件,如下所示: ProcessName Time process1 10 process2 20 processn 30 我读了一些教程,但仍然不能完全理解。对于这个问题,我的mapper和reducer类应该做什么?我的输出将始终是文本文件,还是可以直接将平均值存储在某种变量中 谢谢。您的映射器将您的输入映射到您想要取平均值的值。假设您

我是Hadoop Map/Reduce的新手。我正在尝试编写一个Map/Reduce作业,以查找n个进程所花费的平均时间,给定一个输入文本文件,如下所示:

ProcessName Time
process1    10
process2    20
processn    30
我读了一些教程,但仍然不能完全理解。对于这个问题,我的mapper和reducer类应该做什么?我的输出将始终是文本文件,还是可以直接将平均值存储在某种变量中


谢谢。

您的映射器将您的输入映射到您想要取平均值的值。假设您的输入是一个文本文件,格式如下

ProcessName Time
process1    10
process2    20
.
.
.
然后,您需要获取文件中的每一行,拆分它,获取第二列,并将该列的值作为
可写
(或其他一些
可写
数字类型)输出。由于您希望取所有时间的平均值,而不是按进程名称或任何内容分组,因此您将有一个固定键。因此,您的映射器看起来像

private IntWritable one = new IntWritable(1);
private IntWritable output = new IntWritable();
proctected void map(LongWritable key, Text value, Context context) {
    String[] fields = value.split("\t");
    output.set(Integer.parseInt(fields[1]));
    context.write(one, output);
}
IntWritable one = new IntWritable(1);
DoubleWritable average = new DoubleWritable();
protected void reduce(IntWritable key, Iterable<IntWrtiable> values, Context context) {
    int sum = 0;
    int count = 0;
    for(IntWritable value : values) {
        sum += value.get();
        count++;
    }
    average.set(sum / (double) count);
    context.Write(key, average);
}
您的减缩器接受这些值,并简单地计算平均值。这看起来像

private IntWritable one = new IntWritable(1);
private IntWritable output = new IntWritable();
proctected void map(LongWritable key, Text value, Context context) {
    String[] fields = value.split("\t");
    output.set(Integer.parseInt(fields[1]));
    context.write(one, output);
}
IntWritable one = new IntWritable(1);
DoubleWritable average = new DoubleWritable();
protected void reduce(IntWritable key, Iterable<IntWrtiable> values, Context context) {
    int sum = 0;
    int count = 0;
    for(IntWritable value : values) {
        sum += value.get();
        count++;
    }
    average.set(sum / (double) count);
    context.Write(key, average);
}
IntWritable one=新的IntWritable(1);
DoubleWritable average=新的DoubleWritable();
受保护的void reduce(可写键、可写值、上下文){
整数和=0;
整数计数=0;
for(可写入值:值){
sum+=value.get();
计数++;
}
平均值。集合(总和/(双重)计数);
context.Write(键,平均值);
}
我在这里做了很多假设,关于你的输入格式等等,但这些都是合理的假设,你应该能够根据自己的具体需要来调整这些假设

我的输出将始终是文本文件,还是可以直接将平均值存储在某种变量中


你有几个选择。例如,您可以对作业的输出进行后期处理(写入单个文件),或者,由于您正在计算单个值,因此可以将结果存储在计数器中。

您的映射程序读取文本文件,并在每一行上应用以下映射函数

map: (key, value)
  time = value[2]
  emit("1", time)
所有映射调用都会发出键“1”,该键将由一个reduce函数处理

reduce: (key, values)
  result = sum(values) / n
  emit("1", result)
由于您使用的是Hadoop,您可能已经在map函数中看到了StringTokenizer的使用,您可以使用它仅获取一行中的时间。此外,您还可以考虑一些计算n(进程数)的方法,例如,您可以在另一个作业中使用计数器,该计数器只计算行数

更新
如果要执行此作业,则必须为每行发送一个元组到reducer,如果在多台计算机上运行Hadoop集群,则可能会阻塞网络。 更聪明的方法可以计算更接近输入的时间之和,例如通过指定组合器:

combine: (key, values)
  emit(key, sum(values))
然后在同一台机器的所有映射函数的结果上执行该组合器,即在两者之间没有联网。
这样,reducer将只获得集群中机器的元组数量,而不是日志文件中的行数。

谢谢。还有一件事。我已经建立了一个hadoop集群,其中包含1个作业跟踪器和3个其他任务跟踪器。那么,我是否需要将输入文件保存在所有任务跟踪器中,或者如果仅将其保存在工作跟踪器中,是否就足够了?有没有办法确定作业是否均匀地分布到所有从节点?HDFS和Hadoop将为您处理。您可以通过打开Hadoop作业跟踪器节点上的端口50030(至少是默认端口)来监视作业,并从那里访问任务跟踪器。请注意,由于映射作业中只有一个输出键,因此reduce任务将仅在一个节点上运行。谢谢。还有一件事。有没有办法确定作业是否均匀分布到所有从属节点?我有一个包含1个主节点和3个从节点的集群。您放入HDFS的文件被拆分为几个块,这些块将复制到您的集群上(请参阅:)。然后在每个集群上为每个块实例化映射器类。碰巧两个映射器可以在不同集群的同一块上工作,然后碰巧一个“赢”,另一个被中止,中间结果被丢弃。如果你想分析你的工作,你必须查看你的工作日志。jobtracker的webinterface提供了一些统计数据。这是一个例子,说明了设计糟糕的Hadoop算法是多么无用。@horcrux请详细说明。@。因此,整个工作是由一名工人完成的。因此,您需要一个愚蠢的avg()方法的计算能力,这个方法可以由一台机器执行。相反,您只是增加了网络开销。可能会重复