所有網(wǎng)站的服務(wù)器上都會(huì)保留訪問的log日志水由。這些log日志記錄的其他機(jī)器訪問服務(wù)器的ip欲主,時(shí)間募疮,http協(xié)議芍锚,狀態(tài)碼等信息昔园。
比如這樣:
大型網(wǎng)站的服務(wù)器往往會(huì)產(chǎn)生海量的log日志,用hadoop來分析log日志并炮,也是一個(gè)很好的練手的機(jī)會(huì)潘拱。
下面寫一個(gè)例子屋吨,通過分析服務(wù)器的log日志,統(tǒng)計(jì)訪問服務(wù)器的ip地址和訪問的次數(shù)。
map函數(shù)
public class worldcount extends Mapper<LongWritable,Text,Text,IntWritable>{
//重載Mapper類的map方法
// 這里的key是讀取文件的行號(hào)呛占,value是對(duì)應(yīng)行號(hào)的文本
protected void map(LongWritable key,Text value,Context context) throws IOException, InterruptedException{
//將這一行轉(zhuǎn)化為string
String line=value.toString();
//以空格切分
String [] linewords = line.split(" ");
//獲得ip
String ip=linewords[0];
// 所以在context里面寫的內(nèi)容就是 key:ip ,value 是1
context.write(new Text(ip), new IntWritable(1));
}
}
<br />
reduce 函數(shù)
public class worldcountreduce extends Reducer <Text,IntWritable,Text,IntWritable> {
// 一組相同的key叽掘,調(diào)用一次reduce
//相當(dāng)于調(diào)用一次 蚣抗,計(jì)算一個(gè)key對(duì)應(yīng)的個(gè)數(shù)
protected void reduce (Text key,Iterable<IntWritable> values,Context context) throws IOException, InterruptedException{
//統(tǒng)計(jì)單詞數(shù)
int count=0;
for(IntWritable value :values){
count=count+value.get();
}
//將輸出的結(jié)果放到context 里面
context.write(key,new IntWritable(count));
}
}
<br />
Main 函數(shù)
public class jobclient {
public static void main(String []args) throws IOException, ReflectiveOperationException, InterruptedException{
Configuration conf=new Configuration();
//conf.set("yarn.resoucemanager.hostname", value);
Job job=Job.getInstance(conf);
//job.setJar("~/code/WordCount.jar");
//告知客戶端的提交器 mr程序所在的jar包
//這樣就不必使用setjar 這樣的方法了
job.setJarByClass(jobclient.class);
// 告知mrapp master ,map 和reduce 對(duì)應(yīng)的實(shí)現(xiàn)類
job.setMapperClass(worldcount.class);
job.setReducerClass(worldcountreduce.class);
//告知輸入癌瘾,和輸出的數(shù)據(jù)結(jié)構(gòu)的類型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//告知mrappmaster 我們啟動(dòng)的reduce tash的數(shù)量
//啟動(dòng)maptask 的數(shù)量 是yarn 會(huì)自動(dòng)的計(jì)算
job.setNumReduceTasks(3);
//指定一個(gè)目錄而不是文件
FileInputFormat.setInputPaths(job, new Path("hdfs://localhost:9000/kpi/"));
FileOutputFormat.setOutputPath(job,new Path("hdfs://localhost:9000/kpi/output/"));
// job.submit()
//這個(gè)要比job.submit 要好觅丰,因?yàn)檫@個(gè)client并不會(huì)在提交任務(wù)之后,就退出妨退,而是創(chuàng)建一個(gè)線程去監(jiān)控 map和reduce的運(yùn)行
boolean res=job.waitForCompletion(true);
// 執(zhí)行成功 狀態(tài)嗎 是0妇萄,執(zhí)行失敗 狀態(tài)碼是100
// 通過echo $? 顯示狀態(tài)碼
System.out.println("wakakka ");
System.exit(res?0:100);
}
}
這里的輸入是一個(gè)目錄,可以把輸入的文件放到這個(gè)目錄里面就好碧注。比如這里嚣伐,我把a(bǔ)ccess.log.10文件放在kpi目錄下面。
然后將代碼打包為一個(gè)jar包萍丐,使用hadoo命令執(zhí)行這個(gè)jar包轩端。(執(zhí)行這條命令必須在jar包所在的目錄下面執(zhí)行)
程序運(yùn)行的結(jié)果是在輸出的目錄里面:
查看一個(gè)文件,就是程序的運(yùn)行結(jié)果:
關(guān)于代碼的一些小結(jié):
- hadoop經(jīng)常啟動(dòng)失敗逝变,或者出現(xiàn)訪問失敗的情況基茵。
- 在寫代碼之前拱层,一定要把所有的關(guān)于hadoop根灯,mapreduce的包導(dǎo)入纳猪。
- 將代碼打包為一個(gè)jar包氏堤。
github地址:
https://github.com/zhaozhengcoder/hadoop/tree/master/mapreduce_kpi