本文通過一個完整的 MapReduce 程式範例,演示如何從日誌數據中統計不同省份用戶的訪問次數。涵蓋需求分析、核心代碼實現、運行指令與結果展示,適合大數據入門開發者參考。
針對日誌文件中的字段信息,統計網站中不同省份用戶的訪問數量。假設日誌格式為制表符(\t)分隔,第 2 欄為 URL,第 24 欄(索引 23)為省份 ID。
完整程式包含 Mapper、Reducer、Driver 三大部分,採用新版 MapReduce API (org.apache.hadoop.mapreduce)。
public static class ProvinceCountMapper
extends Mapper<LongWritable, Text, IntWritable, IntWritable> {
private IntWritable outKey = new IntWritable();
private static final IntWritable ONE = new IntWritable(1);
@Override
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
String line = value.toString();
String[] fields = line.split("\t");
// 數據清洗:字段數不足、URL或省份ID為空直接返回
if (fields.length < 30 || StringUtils.isBlank(fields[1]) || StringUtils.isBlank(fields[23])) {
return;
}
String provinceIdStr = fields[23];
int provinceId;
try {
provinceId = Integer.parseInt(provinceIdStr);
} catch (NumberFormatException e) {
return; // 非數字省份ID忽略
}
if (provinceId == Integer.MAX_VALUE) return; // 過濾異常值
outKey.set(provinceId);
context.write(outKey, ONE);
}
}
public static class ProvinceCountReducer
extends Reducer<IntWritable, IntWritable, IntWritable, IntWritable> {
private IntWritable result = new IntWritable();
@Override
protected void reduce(IntWritable key, Iterable<IntWritable> values, Context context)
throws IOException, InterruptedException {
int sum = 0;
for (IntWritable val : values) {
sum += val.get();
}
result.set(sum);
context.write(key, result);
}
}
public class ProvinceCountMapReduce extends Configured implements Tool {
@Override
public int run(String[] args) throws Exception {
Configuration conf = getConf();
Job job = Job.getInstance(conf, "ProvinceVisitCount");
job.setJarByClass(ProvinceCountMapReduce.class);
// 輸入輸出路徑
FileInputFormat.addInputPath(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
// Mapper 配置
job.setMapperClass(ProvinceCountMapper.class);
job.setMapOutputKeyClass(IntWritable.class);
job.setMapOutputValueClass(IntWritable.class);
// Reducer 配置
job.setReducerClass(ProvinceCountReducer.class);
job.setOutputKeyClass(IntWritable.class);
job.setOutputValueClass(IntWritable.class);
// 啟用 Map 輸出壓縮優化網絡傳輸
conf.set("mapreduce.map.output.compress", "true");
return job.waitForCompletion(true) ? 0 : 1;
}
public static void main(String[] args) throws Exception {
// 測試參數:HDFS 輸入輸出路徑
String[] testArgs = {
"hdfs://Hadoop-senior02.beifeng.com:8020/input/2015082818",
"hdfs://Hadoop-senior02.beifeng.com:8020/output15/"
};
Configuration conf = new Configuration();
int status = ToolRunner.run(conf, new ProvinceCountMapReduce(), testArgs);
System.exit(status);
}
}
bin/hdfs dfs -text /output15/part*
1 3527
2 1672
3 511
4 325
5 776
6 661
7 95
8 80
9 183
10 93
... (省略部分省份)
32 173
結果顯示各省份 ID 對應的訪問次數,省份 1 訪問量最高(3527 次),省份 22 最低(38 次)。
IntWritable 確保鍵值類型匹配,避免序列化錯誤。mapreduce.map.output.compress),減少 Shuffle 階段網絡 I/O。Tool 介面,支援通用命令行參數解析與配置復用。