我正在構建 mapreducer 應用程式,它將帶有亂數的 .txt 作為輸入,我想接收這樣的輸出資訊:
最大數:xx 算術平均:xx 幾何平均:xx 中位數:xx
我的代碼:
import java.io.IOException;
import java.util.StringTokenizer;
import java.util.*;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class NumCount {
public static class TokenizerMapper
extends Mapper<Object, Text, Text, IntWritable>{
private final static IntWritable one = new IntWritable(1);
private Text number = new Text();
public void map(Object key, Text value, Context context
) throws IOException, InterruptedException {
StringTokenizer itr = new StringTokenizer(value.toString());
while (itr.hasMoreTokens()) {
number.set(itr.nextToken());
context.write(number, one);
}
}
}
public static class IntSumReducer
extends Reducer<Text,IntWritable,Text,IntWritable> {
private IntWritable result = new IntWritable();
public void reduce(Text key, Iterable<IntWritable> values,
Context context
) throws IOException, InterruptedException {
List<Integer> numList = new ArrayList<Integer>();
for (IntWritable val : values) {
numList.add(val.get());
}
// Max number from file
int maxNumber = Collections.max(numList,null);
// Arithmetic average
float sum = 0;
for (int i : numList)
sum = i;
float arithmeticAverage = sum / numList.size();
// Geometric average
sum = 1;
for (int i : numList)
sum *= i;
double geometricAverage = Math.pow(sum, (float)1/numList.size());
// Median
float median;
if (numList.size() % 2 == 0)
median = (float)(numList.get(numList.size()/2) numList.get(numList.size()/2 - 1))/2;
else
median = numList.get(numList.size()/2);
String summary = "Max number: " maxNumber "\nArithmetic avg: " arithmeticAverage "\nGeometric avg: " geometricAverage "\nMedian" median;
result.set(summary);
context.write(key, result);
}
}
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf, "number count");
job.setJarByClass(NumCount.class);
job.setMapperClass(TokenizerMapper.class);
job.setCombinerClass(IntSumReducer.class);
job.setReducerClass(IntSumReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
FileInputFormat.addInputPath(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
我的代碼的問題是,我收到無法將字串放入 IntWritable 的錯誤(看起來很邏輯,但是如何將字串值決議為輸出?)
result.set(summary);
更重要的是,當我嘗試做這樣的事情時:
result.set(median);
我沒有收到中值,而是收到了錯誤的輸出,這是來自輸入檔案的數字串列,附近有“1”。
我對hadoop完全陌生,我不知道如何正確地做到這一點,有什么建議嗎?;X
uj5u.com熱心網友回復:
既然你有String summary,顯然答案是使用Text 而不是IntWritable......IntWritable如果你有多個值要回傳,則不要使用,其中多個不是整數。
此外,這個邏輯甚至不正確,因為所有相等的數字最終都在同一個減速器中,因此“maxNumber”永遠不會是整體最大值,因此您將擁有與唯一輸入值相同的減速器輸出值. 解決方案是NullWritable用作 reducer 鍵(和映射器鍵輸出),將所有數字強制放入一個 reducer,以便它們可以最大化/平均/求和等。您也不需要,numList因為Iterable<IntWritable>已經能夠迭代;你應該只需要一個回圈來完成所有的計算,除了中位數,你需要先對數字進行排序。
我個人的建議是使用 Spark 或 Hive 進行統計分析,而不是使用準系統 Mapreduce ...
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/405765.html
標籤:
下一篇:列中相同值的最小時間戳磁區
