需要帮助编写map/reduce作业来找到平均值吗

jutyujz0  于 2021-06-03  发布在  Hadoop
关注(0)|答案(2)|浏览(286)

我对hadoop map/reduce还比较陌生。我正在尝试编写一个map/reduce作业,以查找n个进程所用的平均时间,给定一个输入文本文件,如下所示:

ProcessName Time
process1    10
process2    20
processn    30

我读了一些教程,但还是不能完全理解。我的mapper和reducer类应该如何解决这个问题?我的输出总是文本文件还是可以直接将平均值存储在某种变量中?
谢谢。

slwdgvem

slwdgvem1#

Map程序读取文本文件,并在每行上应用以下Map函数

map: (key, value)
  time = value[2]
  emit("1", time)

所有map调用都会发出键“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))

然后,在同一机器的所有map函数的结果上执行该组合器,即,在两者之间没有联网。这样,reducer只会得到集群中机器数量的元组,而不是日志文件中的行数。

ymdaylpp

ymdaylpp2#

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

ProcessName Time
process1    10
process2    20
.
.
.

然后您需要获取文件中的每一行,拆分它,获取第二列,并将该列的值作为 IntWritable (或其他 Writable 数字类型)。因为您希望取所有时间的平均值,而不是按进程名或任何东西分组,所以您将有一个固定键。因此,您的Map器看起来像

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);
}

我在这里做了很多假设,关于你的输入格式什么的,但是这些都是合理的假设,你应该能够调整这些来满足你的确切需求。
我的输出总是文本文件还是可以直接将平均值存储在某种变量中?
你有几个选择。例如,您可以对作业的输出进行后处理(写入单个文件),或者,由于您计算的是单个值,因此可以将结果存储在计数器中。

相关问题