大数据Web日志分析 用Hadoop统计KPI指标实例

可以带着下面问题来阅读文章
问题:
1.MapReduce在日志分析的作用

思考:
该如何架构kpi系统,需要考虑什么问题。

kpi:关键绩效指标法,即KPI绩效考核,是企业绩效考核的方法之一,其特点是考核指标围绕关键成果领域进行选取,均对关键绩效指标考核法的应用及其特点有所介绍。
前言
Web日志包含着网站最重要的信息,通过日志分析,我们可以知道网站的访问量,哪个网页访问人数最多,哪个网页最有价值等。一般中型的网站(10W的PV以上),每天会产生1G以上Web日志文件。大型或超大型的网站,可能每小时就会产生10G的数据量。
对于日志的这种规模的数据,用Hadoop进行日志分析,是最适合不过的了。
目录
  • Web日志分析概述
  • 需求分析:KPI指标设计
  • 算法模型:Hadoop并行算法
  • 架构设计:日志KPI系统架构
  • 程序开发1:用Maven构建Hadoop项目
  • 程序开发2:MapReduce程序实现
1. Web日志分析概述 Web日志由Web服务器产生,可能是Nginx, Apache, Tomcat等。从Web日志中,我们可以获取网站每类页面的PV值(PageView,页面访问量)、独立IP数;稍微复杂一些的,可以计算得出用户所检索的关键词排行榜、用户停留时间最高的页面等;更复杂的,构建广告点击模型、分析用户行为特征等等。
在Web日志中,每条日志通常代表着用户的一次访问行为,例如下面就是一条nginx日志:
  1. 222.68.172.190 - - [18/Sep/2013:06:49:57 +0000] "GET /images/my.jpg HTTP/1.1" 200 19939
  2. "http://www.angularjs.cn/A00n" "Mozilla/5.0 (Windows NT 6.1)
  3. AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36"
复制代码
拆解为以下8个变量
  • remote_addr: 记录客户端的ip地址, 222.68.172.190
  • remote_user: 记录客户端用户名称, –
  • time_local: 记录访问时间与时区, [18/Sep/2013:06:49:57 +0000]
  • request: 记录请求的url与http协议, “GET /images/my.jpg HTTP/1.1″
  • status: 记录请求状态,成功是200, 200
  • body_bytes_sent: 记录发送给客户端文件主体内容大小, 19939
  • http_referer: 用来记录从那个页面链接访问过来的, “http://www.angularjs.cn/A00n
  • http_user_agent: 记录客户浏览器的相关信息, “Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36″
注:要更多的信息,则要用其它手段去获取,通过js代码单独发送请求,使用cookies记录用户的访问信息。
利用这些日志信息,我们可以深入挖掘网站的秘密了。
少量数据的情况
少量数据的情况(10Mb,100Mb,10G),在单机处理尚能忍受的时候,我可以直接利用各种Unix/Linux工具,awk、grep、sort、join等都是日志分析的利器,再配合perl, python,正则表达工,基本就可以解决所有的问题。
例如,我们想从上面提到的nginx日志中得到访问量最高前10个IP,实现很简单:
  1. ~ cat access.log.10 | awk '{a[$1]++} END {for(b in a) print b"\t"a[b]}' | sort -k2 -r | head -n 10
  2. 163.177.71.12   972
  3. 101.226.68.137  972
  4. 183.195.232.138 971
  5. 50.116.27.194   97
  6. 14.17.29.86     96
  7. 61.135.216.104  94
  8. 61.135.216.105  91
  9. 61.186.190.41   9
  10. 59.39.192.108   9
  11. 220.181.51.212  9
复制代码
海量数据的情况
当数据量每天以10G、100G增长的时候,单机处理能力已经不能满足需求。我们就需要增加系统的复杂性,用计算机集群,存储阵列来解决。在Hadoop出现之前,海量数据存储,和海量日志分析都是非常困难的。只有少数一些公司,掌握着高效的并行计算,分步式计算,分步式存储的核心技术。
Hadoop的出现,大幅度的降低了海量数据处理的门槛,让小公司甚至是个人都能力,搞定海量数据。并且,Hadoop非常适用于日志分析系统。
2.需求分析:KPI指标设计 下面我们将从一个公司案例出发来全面的解释,如何用进行 海量Web日志分析,提取KPI数据。
案例介绍
某电子商务网站,在线团购业务。每日PV数100w,独立IP数5w。用户通常在工作日上午10:00-12:00和下午15:00-18:00访问量最大。日间主要是通过PC端浏览器访问,休息日及夜间通过移动设备访问较多。网站搜索浏量占整个网站的80%,PC用户不足1%的用户会消费,移动用户有5%会消费。
通过简短的描述,我们可以粗略地看出,这家电商网站的经营状况,并认识到愿意消费的用户从哪里来,有哪些潜在的用户可以挖掘,网站是否存在倒闭风险等。
KPI指标设计
  • PV(PageView): 页面访问量统计
  • IP: 页面独立IP的访问量统计
  • Time: 用户每小时PV的统计
  • Source: 用户来源域名的统计
  • Browser: 用户的访问设备统计
注:商业保密限制,无法提供电商网站的日志。

3.算法模型:Hadoop并行算法 基本统计指标:
 
用户的访问设备统计指标:
 
从商业的角度,个人网站的特征与电商网站不太一样,没有转化率,同时跳出率也比较高。从技术的角度,同样都关注KPI指标设计。
3.算法模型:Hadoop并行算法  
并行算法的设计:
注:找到第一节有定义的8个变量
PV(PageView): 页面访问量统计
  • Map过程{key:$request,value:1}
  • Reduce过程{key:$request,value:求和(sum)}
IP: 页面独立IP的访问量统计
  • Map: {key:$request,value:$remote_addr}
  • Reduce: {key:$request,value:去重再求和(sum(unique))}
Time: 用户每小时PV的统计
  • Map: {key:$time_local,value:1}
  • Reduce: {key:$time_local,value:求和(sum)}
Source: 用户来源域名的统计
  • Map: {key:$http_referer,value:1}
  • Reduce: {key:$http_referer,value:求和(sum)}
Browser: 用户的访问设备统计
  • Map: {key:$http_user_agent,value:1}
  • Reduce: {key:$http_user_agent,value:求和(sum)}
4.架构设计:日志KPI系统架构   
上图中,左边是Application业务系统,右边是Hadoop的HDFS, MapReduce。
  • 日志是由业务系统产生的,我们可以设置web服务器每天产生一个新的目录,目录下面会产生多个日志文件,每个日志文件64M。
  • 设置系统定时器CRON,夜间在0点后,向HDFS导入昨天的日志文件。
  • 完成导入后,设置系统定时器,启动MapReduce程序,提取并计算统计指标。
  • 完成计算后,设置系统定时器,从HDFS导出统计指标数据到数据库,方便以后的即使查询。
 
上面这幅图,我们可以看得更清楚,数据是如何流动的。蓝色背景的部分是在Hadoop中的,接下来我们的任务就是完成MapReduce的程序实现。
5.程序开发1:用Maven构建Hadoop项目 请参考文章: 用Maven构建Hadoop项目
win7的开发环境 和 Hadoop的运行环境 ,在上面文章中已经介绍过了。

我们需要放日志文件,上传的HDFS里/user/hdfs/log_kpi/目录,参考下面的命令操作
  1. ~ hadoop fs -mkdir /user/hdfs/log_kpi
  2. ~ hadoop fs -copyFromLocal /home/conan/datafiles/access.log.10 /user/hdfs/log_kpi/
复制代码
我已经把整个MapReduce的实现都放到了github上面:
  1. https://github.com/bsspirit/maven_hadoop_template/releases/tag/kpi_v1
复制代码
6.程序开发2:MapReduce程序实现 开发流程:
  • 对日志行的解析
  • Map函数实现
  • Reduce函数实现
  • 启动程序实现
1). 对日志行的解析
新建文件:org.conan.myhadoop.mr.kpi.KPI.java
  1. package org.conan.myhadoop.mr.kpi;

  2. import java.text.ParseException;
  3. import java.text.SimpleDateFormat;
  4. import java.util.Date;
  5. import java.util.Locale;

  6. /*
  7. * KPI Object
  8. */
  9. public class KPI {
  10.     private String remote_addr;// 记录客户端的ip地址
  11.     private String remote_user;// 记录客户端用户名称,忽略属性"-"
  12.     private String time_local;// 记录访问时间与时区
  13.     private String request;// 记录请求的url与http协议
  14.     private String status;// 记录请求状态;成功是200
  15.     private String body_bytes_sent;// 记录发送给客户端文件主体内容大小
  16.     private String http_referer;// 用来记录从那个页面链接访问过来的
  17.     private String http_user_agent;// 记录客户浏览器的相关信息

  18.     private boolean valid = true;// 判断数据是否合法
  19.     
  20.     @Override
  21.     public String toString() {
  22.         StringBuilder sb = new StringBuilder();
  23.         sb.append("valid:" + this.valid);
  24.         sb.append("\nremote_addr:" + this.remote_addr);
  25.         sb.append("\nremote_user:" + this.remote_user);
  26.         sb.append("\ntime_local:" + this.time_local);
  27.         sb.append("\nrequest:" + this.request);
  28.         sb.append("\nstatus:" + this.status);
  29.         sb.append("\nbody_bytes_sent:" + this.body_bytes_sent);
  30.         sb.append("\nhttp_referer:" + this.http_referer);
  31.         sb.append("\nhttp_user_agent:" + this.http_user_agent);
  32.         return sb.toString();
  33.     }

  34.     public String getRemote_addr() {
  35.         return remote_addr;
  36.     }

  37.     public void setRemote_addr(String remote_addr) {
  38.         this.remote_addr = remote_addr;
  39.     }

  40.     public String getRemote_user() {
  41.         return remote_user;
  42.     }

  43.     public void setRemote_user(String remote_user) {
  44.         this.remote_user = remote_user;
  45.     }

  46.     public String getTime_local() {
  47.         return time_local;
  48.     }

  49.     public Date getTime_local_Date() throws ParseException {
  50.         SimpleDateFormat df = new SimpleDateFormat("dd/MMM/yyyy:HH:mm:ss", Locale.US);
  51.         return df.parse(this.time_local);
  52.     }
  53.     
  54.     public String getTime_local_Date_hour() throws ParseException{
  55.         SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHH");
  56.         return df.format(this.getTime_local_Date());
  57.     }

  58.     public void setTime_local(String time_local) {
  59.         this.time_local = time_local;
  60.     }

  61.     public String getRequest() {
  62.         return request;
  63.     }

  64.     public void setRequest(String request) {
  65.         this.request = request;
  66.     }

  67.     public String getStatus() {
  68.         return status;
  69.     }

  70.     public void setStatus(String status) {
  71.         this.status = status;
  72.     }

  73.     public String getBody_bytes_sent() {
  74.         return body_bytes_sent;
  75.     }

  76.     public void setBody_bytes_sent(String body_bytes_sent) {
  77.         this.body_bytes_sent = body_bytes_sent;
  78.     }

  79.     public String getHttp_referer() {
  80.         return http_referer;
  81.     }
  82.     
  83.     public String getHttp_referer_domain(){
  84.         if(http_referer.length()<8){ 
  85.             return http_referer;
  86.         }
  87.         
  88.         String str=this.http_referer.replace("\"", "").replace("http://", "").replace("https://", "");
  89.         return str.indexOf("/")>0?str.substring(0, str.indexOf("/")):str;
  90.     }

  91.     public void setHttp_referer(String http_referer) {
  92.         this.http_referer = http_referer;
  93.     }

  94.     public String getHttp_user_agent() {
  95.         return http_user_agent;
  96.     }

  97.     public void setHttp_user_agent(String http_user_agent) {
  98.         this.http_user_agent = http_user_agent;
  99.     }

  100.     public boolean isValid() {
  101.         return valid;
  102.     }

  103.     public void setValid(boolean valid) {
  104.         this.valid = valid;
  105.     }

  106.     public static void main(String args[]) {
  107.         String line = "222.68.172.190 - - [18/Sep/2013:06:49:57 +0000] \"GET /images/my.jpg HTTP/1.1\" 200 19939 \"http://www.angularjs.cn/A00n\" \"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36\"";
  108.         System.out.println(line);
  109.         KPI kpi = new KPI();
  110.         String[] arr = line.split(" ");

  111.         kpi.setRemote_addr(arr[0]);
  112.         kpi.setRemote_user(arr[1]);
  113.         kpi.setTime_local(arr[3].substring(1));
  114.         kpi.setRequest(arr[6]);
  115.         kpi.setStatus(arr[8]);
  116.         kpi.setBody_bytes_sent(arr[9]);
  117.         kpi.setHttp_referer(arr[10]);
  118.         kpi.setHttp_user_agent(arr[11] + " " + arr[12]);
  119.         System.out.println(kpi);

  120.         try {
  121.             SimpleDateFormat df = new SimpleDateFormat("yyyy.MM.dd:HH:mm:ss", Locale.US);
  122.             System.out.println(df.format(kpi.getTime_local_Date()));
  123.             System.out.println(kpi.getTime_local_Date_hour());
  124.             System.out.println(kpi.getHttp_referer_domain());
  125.         } catch (ParseException e) {
  126.             e.printStackTrace();
  127.         }
  128.     }

  129. }
复制代码
从日志文件中,取一行通过main函数写一个简单的解析测试。
控制台输出:
  1. 222.68.172.190 - - [18/Sep/2013:06:49:57 +0000] "GET /images/my.jpg HTTP/1.1" 200 19939 "http://www.angularjs.cn/A00n" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36"
  2. valid:true
  3. remote_addr:222.68.172.190
  4. remote_user:-
  5. time_local:18/Sep/2013:06:49:57
  6. request:/images/my.jpg
  7. status:200
  8. body_bytes_sent:19939
  9. http_referer:"http://www.angularjs.cn/A00n"
  10. http_user_agent:"Mozilla/5.0 (Windows
  11. 2013.09.18:06:49:57
  12. 2013091806
  13. www.angularjs.cn
复制代码
我们看到日志行,被正确的解析成了kpi对象的属性。我们把解析过程,单独封装成一个方法。
  1.   private static KPI parser(String line) {
  2.         System.out.println(line);
  3.         KPI kpi = new KPI();
  4.         String[] arr = line.split(" ");
  5.         if (arr.length > 11) {
  6.             kpi.setRemote_addr(arr[0]);
  7.             kpi.setRemote_user(arr[1]);
  8.             kpi.setTime_local(arr[3].substring(1));
  9.             kpi.setRequest(arr[6]);
  10.             kpi.setStatus(arr[8]);
  11.             kpi.setBody_bytes_sent(arr[9]);
  12.             kpi.setHttp_referer(arr[10]);
  13.             
  14.             if (arr.length > 12) {
  15.                 kpi.setHttp_user_agent(arr[11] + " " + arr[12]);
  16.             } else {
  17.                 kpi.setHttp_user_agent(arr[11]);
  18.             }

  19.             if (Integer.parseInt(kpi.getStatus()) >= 400) {// 大于400,HTTP错误
  20.                 kpi.setValid(false);
  21.             }
  22.         } else {
  23.             kpi.setValid(false);
  24.         }
  25.         return kpi;
  26.     }
复制代码
对map方法,reduce方法,启动方法,我们单独写一个类来实现
下面将分别介绍MapReduce的实现类:
PV:org.conan.myhadoop.mr.kpi.KPIPV.java
IP: org.conan.myhadoop.mr.kpi.KPIIP.java
Time: org.conan.myhadoop.mr.kpi.KPITime.java
Browser: org.conan.myhadoop.mr.kpi.KPIBrowser.java
1). PV:org.conan.myhadoop.mr.kpi.KPIPV.java
  1. package org.conan.myhadoop.mr.kpi;

  2. import java.io.IOException;
  3. import java.util.Iterator;

  4. import org.apache.hadoop.fs.Path;
  5. import org.apache.hadoop.io.IntWritable;
  6. import org.apache.hadoop.io.Text;
  7. import org.apache.hadoop.mapred.FileInputFormat;
  8. import org.apache.hadoop.mapred.FileOutputFormat;
  9. import org.apache.hadoop.mapred.JobClient;
  10. import org.apache.hadoop.mapred.JobConf;
  11. import org.apache.hadoop.mapred.MapReduceBase;
  12. import org.apache.hadoop.mapred.Mapper;
  13. import org.apache.hadoop.mapred.OutputCollector;
  14. import org.apache.hadoop.mapred.Reducer;
  15. import org.apache.hadoop.mapred.Reporter;
  16. import org.apache.hadoop.mapred.TextInputFormat;
  17. import org.apache.hadoop.mapred.TextOutputFormat;

  18. public class KPIPV { 

  19.     public static class KPIPVMapper extends MapReduceBase implements Mapper {
  20.         private IntWritable one = new IntWritable(1);
  21.         private Text word = new Text();

  22.         @Override
  23.         public void map(Object key, Text value, OutputCollector output, Reporter reporter) throws IOException {
  24.             KPI kpi = KPI.filterPVs(value.toString());
  25.             if (kpi.isValid()) {
  26.                 word.set(kpi.getRequest());
  27.                 output.collect(word, one);
  28.             }
  29.         }
  30.     }

  31.     public static class KPIPVReducer extends MapReduceBase implements Reducer {
  32.         private IntWritable result = new IntWritable();

  33.         @Override
  34.         public void reduce(Text key, Iterator values, OutputCollector output, Reporter reporter) throws IOException {
  35.             int sum = 0;
  36.             while (values.hasNext()) {
  37.                 sum += values.next().get();
  38.             }
  39.             result.set(sum);
  40.             output.collect(key, result);
  41.         }
  42.     }

  43.     public static void main(String[] args) throws Exception {
  44.         String input = "hdfs://192.168.1.210:9000/user/hdfs/log_kpi/";
  45.         String output = "hdfs://192.168.1.210:9000/user/hdfs/log_kpi/pv";

  46.         JobConf conf = new JobConf(KPIPV.class);
  47.         conf.setJobName("KPIPV");
  48.         conf.addResource("classpath:/hadoop/core-site.xml");
  49.         conf.addResource("classpath:/hadoop/hdfs-site.xml");
  50.         conf.addResource("classpath:/hadoop/mapred-site.xml");

  51.         conf.setMapOutputKeyClass(Text.class);
  52.         conf.setMapOutputValueClass(IntWritable.class);

  53.         conf.setOutputKeyClass(Text.class);
  54.         conf.setOutputValueClass(IntWritable.class);

  55.         conf.setMapperClass(KPIPVMapper.class);
  56.         conf.setCombinerClass(KPIPVReducer.class);
  57.         conf.setReducerClass(KPIPVReducer.class);

  58.         conf.setInputFormat(TextInputFormat.class);
  59.         conf.setOutputFormat(TextOutputFormat.class);

  60.         FileInputFormat.setInputPaths(conf, new Path(input));
  61.         FileOutputFormat.setOutputPath(conf, new Path(output));

  62.         JobClient.runJob(conf);
  63.         System.exit(0);
  64.     }
  65. }
复制代码
在程序中会调用KPI类的方法
  1. KPI kpi = KPI.filterPVs(value.toString());
复制代码
通过filterPVs方法,我们可以实现对PV,更多的控制。
在KPK.java中,增加filterPVs方法
  1.    /**
  2.      * 按page的pv分类
  3.      */
  4.     public static KPI filterPVs(String line) {
  5.         KPI kpi = parser(line);
  6.         Set pages = new HashSet();
  7.         pages.add("/about");
  8.         pages.add("/black-ip-list/");
  9.         pages.add("/cassandra-clustor/");
  10.         pages.add("/finance-rhive-repurchase/");
  11.         pages.add("/hadoop-family-roadmap/");
  12.         pages.add("/hadoop-hive-intro/");
  13.         pages.add("/hadoop-zookeeper-intro/");
  14.         pages.add("/hadoop-mahout-roadmap/");

  15.         if (!pages.contains(kpi.getRequest())) {
  16.             kpi.setValid(false);
  17.         }
  18.         return kpi;
  19.     }
复制代码
在filterPVs方法,我们定义了一个pages的过滤,就是只对这个页面进行PV统计。
我们运行一下KPIPV.java
  1. 2013-10-9 11:53:28 org.apache.hadoop.mapred.MapTask$MapOutputBuffer flush
  2. 信息: Starting flush of map output
  3. 2013-10-9 11:53:28 org.apache.hadoop.mapred.MapTask$MapOutputBuffer sortAndSpill
  4. 信息: Finished spill 0
  5. 2013-10-9 11:53:28 org.apache.hadoop.mapred.Task done
  6. 信息: Task:attempt_local_0001_m_000000_0 is done. And is in the process of commiting
  7. 2013-10-9 11:53:30 org.apache.hadoop.mapred.LocalJobRunner$Job statusUpdate
  8. 信息: hdfs://192.168.1.210:9000/user/hdfs/log_kpi/access.log.10:0+3025757
  9. 2013-10-9 11:53:30 org.apache.hadoop.mapred.LocalJobRunner$Job statusUpdate
  10. 信息: hdfs://192.168.1.210:9000/user/hdfs/log_kpi/access.log.10:0+3025757
  11. 2013-10-9 11:53:30 org.apache.hadoop.mapred.Task sendDone
  12. 信息: Task 'attempt_local_0001_m_000000_0' done.
  13. 2013-10-9 11:53:30 org.apache.hadoop.mapred.Task initialize
  14. 信息:  Using ResourceCalculatorPlugin : null
  15. 2013-10-9 11:53:30 org.apache.hadoop.mapred.LocalJobRunner$Job statusUpdate
  16. 信息: 
  17. 2013-10-9 11:53:30 org.apache.hadoop.mapred.Merger$MergeQueue merge
  18. 信息: Merging 1 sorted segments
  19. 2013-10-9 11:53:30 org.apache.hadoop.mapred.Merger$MergeQueue merge
  20. 信息: Down to the last merge-pass, with 1 segments left of total size: 213 bytes
  21. 2013-10-9 11:53:30 org.apache.hadoop.mapred.LocalJobRunner$Job statusUpdate
  22. 信息: 
  23. 2013-10-9 11:53:30 org.apache.hadoop.mapred.Task done
  24. 信息: Task:attempt_local_0001_r_000000_0 is done. And is in the process of commiting
  25. 2013-10-9 11:53:30 org.apache.hadoop.mapred.LocalJobRunner$Job statusUpdate
  26. 信息: 
  27. 2013-10-9 11:53:30 org.apache.hadoop.mapred.Task commit
  28. 信息: Task attempt_local_0001_r_000000_0 is allowed to commit now
  29. 2013-10-9 11:53:30 org.apache.hadoop.mapred.FileOutputCommitter commitTask
  30. 信息: Saved output of task 'attempt_local_0001_r_000000_0' to hdfs://192.168.1.210:9000/user/hdfs/log_kpi/pv
  31. 2013-10-9 11:53:31 org.apache.hadoop.mapred.JobClient monitorAndPrintJob
  32. 信息:  map 100% reduce 0%
  33. 2013-10-9 11:53:33 org.apache.hadoop.mapred.LocalJobRunner$Job statusUpdate
  34. 信息: reduce > reduce
  35. 2013-10-9 11:53:33 org.apache.hadoop.mapred.Task sendDone
  36. 信息: Task 'attempt_local_0001_r_000000_0' done.
  37. 2013-10-9 11:53:34 org.apache.hadoop.mapred.JobClient monitorAndPrintJob
  38. 信息:  map 100% reduce 100%
  39. 2013-10-9 11:53:34 org.apache.hadoop.mapred.JobClient monitorAndPrintJob
  40. 信息: Job complete: job_local_0001
  41. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  42. 信息: Counters: 20
  43. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  44. 信息:   File Input Format Counters 
  45. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  46. 信息:     Bytes Read=3025757
  47. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  48. 信息:   File Output Format Counters 
  49. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  50. 信息:     Bytes Written=183
  51. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  52. 信息:   FileSystemCounters
  53. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  54. 信息:     FILE_BYTES_READ=545
  55. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  56. 信息:     HDFS_BYTES_READ=6051514
  57. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  58. 信息:     FILE_BYTES_WRITTEN=83472
  59. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  60. 信息:     HDFS_BYTES_WRITTEN=183
  61. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  62. 信息:   Map-Reduce Framework
  63. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  64. 信息:     Map output materialized bytes=217
  65. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  66. 信息:     Map input records=14619
  67. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  68. 信息:     Reduce shuffle bytes=0
  69. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  70. 信息:     Spilled Records=16
  71. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  72. 信息:     Map output bytes=2004
  73. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  74. 信息:     Total committed heap usage (bytes)=376569856
  75. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  76. 信息:     Map input bytes=3025757
  77. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  78. 信息:     SPLIT_RAW_BYTES=110
  79. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  80. 信息:     Combine input records=76
  81. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  82. 信息:     Reduce input records=8
  83. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  84. 信息:     Reduce input groups=8
  85. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  86. 信息:     Combine output records=8
  87. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  88. 信息:     Reduce output records=8
  89. 2013-10-9 11:53:34 org.apache.hadoop.mapred.Counters log
  90. 信息:     Map output records=76
复制代码
用hadoop命令查看HDFS文件
  1. ~ hadoop fs -cat /user/hdfs/log_kpi/pv/part-00000

  2. /about  5
  3. /black-ip-list/ 2
  4. /cassandra-clustor/     3
  5. /finance-rhive-repurchase/      13
  6. /hadoop-family-roadmap/ 13
  7. /hadoop-hive-intro/     14
  8. /hadoop-mahout-roadmap/ 20
  9. /hadoop-zookeeper-intro/        6
复制代码
这样我们就得到了,刚刚日志文件中的,指定页面的PV值。
指定页面,就像网站的站点地图一样,如果没有指定所有访问链接都会被找出来,通过“站点地图”的指定,我们可以更容易地找到,我们所需要的信息。

源代码下载地址:
http://pan.baidu.com/s/1jG9L2mi


转自:http://www.aboutyun.com/thread-6832-1-1.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值