周旭龍前輩的Hadoop學習筆記—網站日志分析項目案例簡明、經典,業已成為高校大數據相關專業的實驗項目。上周博主也完成了這個實驗,不同於周前輩使用特殊符號切割字符串得到數據的做法,博主使用了正則表達式來匹配數據。在此將我的思路及代碼張貼出來,以供后來者學習借鑒。
一、數據情況分析
1.1、數據格式概覽
本次實驗數據來自於國內某論壇,數據以行為單位,每行記錄由5部分組成,訪問者IP、訪問時間、訪問資源、訪問狀態、訪問流量。
1.2、所需的數據
按照實驗教程,我們只需要IP、時間、uri即可,不過本着既能完成實驗,又能鍛煉鍛煉的想法,我把發個文狀態以及訪問流量也提取了出來。
1.3、上傳數據至HDFS
本次試驗到手的數據大小為60MB,約60萬行。數據量較小,因此直接使用shell命令上傳至HDFS。
注:欲知更詳細的項目背景,請點擊Hadoop學習筆記—網站日志分析項目案例(一)項目介紹__周旭龍_博客園
二、數據清洗准備
2.1、日志解析類
將解析日志信息的功能抽象成為一個日志解析類,分別解析各字段信息。
2.1.1 各字段的正則表達式
IP位於行的開頭,因此定位到行起始位置,向右讀取字符,直到遇到空格。又因為一個有效的IP最少為四個數字+三個符號,7位;最大為3*4+3,15位。所以行起始處7~15位為IP。表達式為:'^\S{7,15}'
時間位於一個方括號內,直接提取方括號內的數據即可:'\[.*?\]'
URI及其相關數據與時間數據位置類似,都在成對符號之內,因此可用相同的解法將其提取出來,再做下一步分析:'\".*?\"'
狀態碼只有三位數,且兩邊都是空格,可以吧兩邊的空格也提出來,再去掉:' \d{3} '
流量在行尾,也都是數字:'\d{1,6}$'
2.1.2 函數
除了一個parse函數以及五個分別處理字段的函數外,正則表達式匹配也抽象成了一個函數。需要注意的是匹配是否為空,以及匹配uri並將其分割為數組后下標取值是否越界。
-
public class parseLine {
-
-
public String[] parse(String line)
-
{
-
String ip = parseIP(line);
-
String time = parseTime(line);
-
String url = parseURL(line);
-
String status = parseStatus(line);
-
String traffic = parseTraffic(line);
-
-
return new String[] {ip,time,url,status,traffic};
-
}
-
-
private String parseReg(String reg,String str)
-
{
-
Pattern pat = Pattern.compile(reg);
-
Matcher matcher = pat.matcher(str);
-
boolean rs = matcher.find();
-
if(rs)
-
return matcher.group(0);
-
else
-
return "null";
-
}
-
-
private String[] splitUrl(String str)
-
{
-
String []urlInfo = str.substring(1, str.length()-1).split(" ");
-
return urlInfo;
-
}
-
-
private String parseTraffic(String line) {
-
String reg_ip = "\\d{1,6}$";
-
return parseReg(reg_ip,line);
-
}
-
-
private String parseStatus(String line) {
-
String reg_ip = " \\d{3} ";
-
return parseReg(reg_ip,line).trim();
-
}
-
-
private String parseURL(String line) {
-
String reg_ip = "\".*?\"";
-
String str = parseReg(reg_ip,line);
-
String[] urlInfo = splitUrl(str);
-
-
return urlInfo[1];
-
}
-
-
private String parseTime(String line) {
-
String reg_ip = "\\[.*?\\]";
-
String str = parseReg(reg_ip,line);
-
SimpleDateFormat in=new SimpleDateFormat("[dd/MMM/yyyy:HH:mm:ss ZZZZZ]",Locale.US);
-
SimpleDateFormat out=new SimpleDateFormat("yyyy年MM月dd日 HH時mm分ss秒");
-
Date d = new Date();
-
try
-
{
-
d=in.parse(str);
-
}
-
catch (ParseException e)
-
{
-
e.printStackTrace();
-
}
-
return out.format(d).trim();
-
}
-
-
private String parseIP(String line) {
-
String reg_ip = "^\\S{7,15}";
-
return parseReg(reg_ip,line);
-
}
-
}
2.2、Mapper類
map階段的輸入為<偏移量,一行文本>,輸出為<偏移量,處理后的數據>。再這個類中,對數據的有效性判斷也在這兒,博主只過濾了靜態數據。
-
public class logMap extends Mapper<LongWritable,Text,LongWritable,Text>{
-
static parseInfo parseLine = new parseInfo();
-
protected void map(LongWritable key1,Text value1,Context context) throws IOException,InterruptedException
-
{
-
String str1 = value1.toString();
-
Text output = new Text();
-
-
final String[] info = parseLine.parse(str1);
-
-
if(info[2].startsWith("/static") || info[2].startsWith("/uc_server"))
-
return ;
-
-
StringBuilder result = new StringBuilder();
-
for(String x:info)
-
result.append(x).append("\t");
-
-
output.set(result.toString());
-
context.write(key1, output);
-
}
-
}
2.3、Reducer類
reduce階段的輸入與map的輸出有關,為<偏移量,處理后數據的集合>,輸出則為<處理后的數據,空>。
-
public class logReducer extends Reducer<LongWritable,Text,Text,NullWritable>{
-
protected void reduce(LongWritable k3,Iterable<Text> v3,Context context) throws IOException,InterruptedException{
-
for(Text v3s : v3)
-
context.write(v3s, NullWritable.get());
-
}
-
}
2.4、主函數
-
public class logMain {
-
-
public static void main(String[] args) throws Exception{
-
Job job = Job.getInstance(new Configuration());
-
job.setJarByClass(logMain.class);
-
-
job.setMapperClass(logMap.class);
-
job.setMapOutputKeyClass(LongWritable.class);
-
job.setMapOutputValueClass(Text.class);
-
-
job.setReducerClass(logReducer.class);
-
job.setOutputKeyClass(Text.class);
-
job.setOutputValueClass(NullWritable.class);
-
-
FileInputFormat.setInputPaths(job, new Path(args[0]));
-
FileOutputFormat.setOutputPath(job, new Path(args[1]));
-
-
job.waitForCompletion(true);
-
}
-
-
}
三、數據清洗
將編寫好的MR到處導出為jar包后,在hadoop中用小規模的測試用例試運行,成功后再用實驗數據。
結果如下:
注:完整項目
Hadoop學習筆記—20.網站日志分析項目案例(一)項目介紹