实现的功能:对采集到的日志数据进行清洗,过滤无效数据、静态资源
方法:编写MapReduce进行处理
1)实体类Bean
描述日志数据的各个字段:如客户端的ip、请求的url、请求状态等等...
2)工具类
用来处理Bean:设置日志的有效或无效,过滤无效日志
3)Map类
编写Map程序
4)Driver类
举一条日志数据为例进行分析:
194.237.142.21 - - [18/Sep/2013:06:49:18 +0000] "GET /wp-content/uploads/2013/07/rstudio-git3.png HTTP/1.1" 304 0 "-" "Mozilla/4.0 (compatible;)"
日志数据都是有一定的规律的。看这条日志数据每个数据彼此之间都是通过空格来隔开的,所以我们可以:
1)每一条日志数据通过空格进行分割;
2)定义一个字符串数组,来接收每一条日志数据;
//创建一个实体Bean对象
WebLogBean webLogBean = new WebLogBean();
//把每一行line代表一条日志数据进行拆分并且存储到一个字符串数组里
String[] arr = line.split(" ");
但并不是所有的日志数据都会像上面的一样,可能有的很短(数据不全),有的很长(用户浏览器信息字段较长)
所以我们要对字符串数组进行判断:
1)字符串长度小于11的,即是数据不全,直接不要
2)长度大于11
长度大于11,并且大于12的,说明最后一个字段:用户浏览器信息过长
此时我们把字符串数组前面的数据写进Bean实体,把字符串数组中关于用户浏览器的字符串存储到一个StringBuilder对象中,最后再写进Bean实体的用户浏览器信息里即可
StringBuilder sb = new StringBuilder();for(int i=11;i<arr.length;i++){ //从a[11]开始,直至末尾,把字段都加进sb里面sb.append(arr[i]);
}
长度大于11,但不大于12的,即长度等于12,“标准”的日志数据,直接把字符串数组各个数据写进Bean实体即可
所以日志数据有三种情况:1、“标准” 2、数据不全 3、数据较长
1)时间
如果字符串数组中获取到的请求时间为“null”或者为空,即把实体"-invalid_time-"写进Bean中
if(null==time_local || "".equals(time_local)) {time_local="-invalid_time-";
}
webLogBean.setTime_local(time_local);
或者说时间没获取到,也认为是无效数据
if("-invalid_time-".Time_local())){webLogBean.setValid(false);
}
2)状态码
如果请求状态码大于400,即说明请求出错,我们视之为无效数据并写入Bean
if (Integer.Status()) >= 400) {// 大于400,HTTP错误webLogBean.setValid(false);
}
3)字符串数组长度
如果字符串数组长度小于11——数据不全,无效!把Bean写为null
webLogBean=null;
4)请求的url不在我们的集合内,视为无效!(集合可自定义)
public static void filtStaticResource(WebLogBean bean, Set<String> pages) {
if (!Request())) {//如果请求的url不在我们定义的集合内,则视为静态资源,设为falsebean.setValid(false);}
}
小结
日志数据:
1、小于11:无效
2、大于11:有效,写入
3、大于12:用户浏览器较长,处理后写入
Bean无效的三个点:
1、时间为空、为null、或者时间获取不到
2、请求为静态资源
3、请求的url不属于集合(自定义)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns=".0.0"xmlns:xsi=""xsi:schemaLocation=".0.0 .0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.chen</groupId><artifactId>bigDataProject_1202ETL</artifactId><version>1.0-SNAPSHOT</version><properties><mavenpiler.source>8</mavenpiler.source><mavenpiler.target>8</mavenpiler.target><!--设置项目的编码为UTF-8--><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><!--使用java8进行编码--><mavenpiler.source>1.8</mavenpiler.source><!--使用java8来进行源码编译--><mavenpiler.target>1.8</mavenpiler.target><!--设置hadoop的版本--><hadoop.version>3.1.2</hadoop.version></properties><!--jar包的依赖--><dependencies><!--测试的依赖坐标--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version></dependency><!--日志打印的依赖坐标--><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.8.2</version></dependency><!--hadoop的通用模块的依赖坐标--><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-common</artifactId><version>${hadoop.version}</version></dependency><!--hadoop的对HDFS分布式文件系统访问的技术支持的依赖坐标--><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-hdfs</artifactId><version>${hadoop.version}</version></dependency><!--hadoop的客户端访问的依赖坐标--><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-client</artifactId><version>${hadoop.version}</version></dependency></dependencies>
</project>
package com.bean;import org.apache.hadoop.io.Writable;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;public class WebLogBean implements Writable {private boolean valid = true;// 判断数据是否合法private String remote_addr;// 记录客户端的ip地址private String remote_user;// 记录客户端用户名称,忽略属性"-"private String time_local;// 记录访问时间与时区private String request;// 记录请求的url与http协议private String status;// 记录请求状态;成功是200private String body_bytes_sent;// 记录发送给客户端文件主体a内容大小private String http_referer;// 用来记录从那个页面链接访问过来的private String http_user_agent;// 记录客户浏览器的相关信息public void set(boolean valid,String remote_addr, String remote_user, String time_local, String request, String status, String body_bytes_sent, String http_referer, String http_user_agent) {this.valid = _addr = remote__user = remote_user;this.time_local = time_quest = request;this.status = status;this.body_bytes_sent = body_bytes_sent;this.http_referer = http_referer;this.http_user_agent = http_user_agent;}public String getRemote_addr() {return remote_addr;}public void setRemote_addr(String remote_addr) {_addr = remote_addr;}public String getRemote_user() {return remote_user;}public void setRemote_user(String remote_user) {_user = remote_user;}public String getTime_local() {return this.time_local;}public void setTime_local(String time_local) {this.time_local = time_local;}public String getRequest() {return request;}public void setRequest(String request) {quest = request;}public String getStatus() {return status;}public void setStatus(String status) {this.status = status;}public String getBody_bytes_sent() {return body_bytes_sent;}public void setBody_bytes_sent(String body_bytes_sent) {this.body_bytes_sent = body_bytes_sent;}public String getHttp_referer() {return http_referer;}public void setHttp_referer(String http_referer) {this.http_referer = http_referer;}public String getHttp_user_agent() {return http_user_agent;}public void setHttp_user_agent(String http_user_agent) {this.http_user_agent = http_user_agent;}public boolean isValid() {return valid;}public void setValid(boolean valid) {this.valid = valid;}/*** 01是hive当中默认的分隔符,不会出现用户手打出来的情况* @return*/@Overridepublic String toString() {StringBuilder sb = new StringBuilder();sb.append(this.valid);sb.append("