关键词:
一、说在前面的话
上一篇,楼主介绍了使用flume集群来模拟网站产生的日志数据收集到hdfs。但我们所采集的日志数据是不规则的,同时也包含了许多无用的日志。当需要分析一些核心指标来满足系统业务决策的时候,对日志的数据清洗在所难免,楼主本篇将介绍如何使用mapreduce程序对日志数据进行清洗,将清洗后的结构化数据存储到hive,并进行相关指标的提取。
先明白几个概念:
1)PV(Page View)。页面浏览量即为PV,是指所有用户浏览页面的总和,一个独立用户每打开一个页面就被记录1 次。计算方式为:记录计数
2)注册用户数。对注册页面访问的次数。计算方式:对访问member.php?mod=register的url,计数
3)IP数。一天之内,访问网站的不同独立IP 个数加和。其中同一IP无论访问了几个页面,独立IP 数均为1。这是我们最熟悉的一个概念,无论同一个IP上有多少台主机,或者其他用户,从某种程度上来说,独立IP的多少,是衡量网站推广活动好坏最直接的数据。计算方式:对不同ip,计数
4)跳出率。只浏览了一个页面便离开了网站的访问次数占总的访问次数的百分比,即只浏览了一个页面的访问次数 / 全部的访问次数汇总。跳出率是非常重要的访客黏性指标,它显示了访客对网站的兴趣程度。跳出率越低说明流量质量越好,访客对网站的内容越感兴趣,这些访客越可能是网站的有效用户、忠实用户。该指标也可以衡量网络营销的效果,指出有多少访客被网络营销吸引到宣传产品页或网站上之后,又流失掉了,可以说就是煮熟的鸭子飞了。比如,网站在某媒体上打广告推广,分析从这个推广来源进入的访客指标,其跳出率可以反映出选择这个媒体是否合适,广告语的撰写是否优秀,以及网站入口页的设计是否用户体验良好。
计算方式:(1)统计一天内只出现一条记录的ip,称为跳出数
(2)跳出数/PV
本次楼主只做以上几项简单指标的分析,各个网站的作用领域不一样,所涉及的分析指标也有很大差别,各位同学可以根据自己的需求尽情拓展。废话不多说,上干货。
二、环境准备
1)hadoop集群。楼主用的6个节点的hadoop2.7.3集群,各位同学可以根据自己的实际情况进行搭建,但至少需要1台伪分布式的。(参考http://www.cnblogs.com/qq503665965/p/6790580.html)
2)hive。用于对各项核心指标进行分析(安装楼主不再介绍了)
3)mysql。存储分析后的数据指标。
4)sqoop。从hive到mysql的数据导入。
三、数据清洗
我们先看看从flume收集到hdfs中的源日志数据格式:
1 27.19.74.143 - - [30/4/2017:17:38:20 +0800] "GET /static/image/common/faq.gif HTTP/1.1" 200 1127 2 211.97.15.179 - - [30/4/2017:17:38:22 +0800] "GET /home.php?mod=misc&ac=sendmail&rand=1369906181 HTTP/1.1" 200 -
上面包含条个静态资源日志和一条正常链接日志(楼主这里不做静态资源日志的分析),需要将以 /static 开头的日志文件过滤掉;时间格式需要转换为时间戳;去掉IP与时间之间的无用符号;过滤掉请求方式;“/”分隔符、http协议、请求状态及当次流量。效果如下:
1 211.97.15.179 20170430173820 home.php?mod=misc&ac=sendmail&rand=1369906181
先写个日志解析类,测试是否能解析成功,我们再写mapreduce程序:
1 package mapreduce; 2 3 import java.text.ParseException; 4 import java.text.SimpleDateFormat; 5 import java.util.Date; 6 import java.util.Locale; 7 8 9 public class LogParser { 10 public static final SimpleDateFormat FORMAT = new SimpleDateFormat("d/MM/yyyy:HH:mm:ss", Locale.ENGLISH); 11 public static final SimpleDateFormat dateformat1=new SimpleDateFormat("yyyyMMddHHmmss"); 12 public static void main(String[] args) throws ParseException { 13 final String S1 = "27.19.74.143 - - [30/04/2017:17:38:20 +0800] \"GET /static/image/common/faq.gif HTTP/1.1\" 200 1127"; 14 LogParser parser = new LogParser(); 15 final String[] array = parser.parse(S1); 16 System.out.println("源数据: "+S1); 17 System.out.format("清洗结果数据: ip=%s, time=%s, url=%s, status=%s, traffic=%s", array[0], array[1], array[2], array[3], array[4]); 18 } 19 /** 20 * 解析英文时间字符串 21 * @param string 22 * @return 23 * @throws ParseException 24 */ 25 private Date parseDateFormat(String string){ 26 Date parse = null; 27 try { 28 parse = FORMAT.parse(string); 29 } catch (ParseException e) { 30 e.printStackTrace(); 31 } 32 return parse; 33 } 34 /** 35 * 解析日志的行记录 36 * @param line 37 * @return 数组含有5个元素,分别是ip、时间、url、状态、流量 38 */ 39 public String[] parse(String line){ 40 String ip = parseIP(line); 41 String time = parseTime(line); 42 String url = parseURL(line); 43 String status = parseStatus(line); 44 String traffic = parseTraffic(line); 45 46 return new String[]{ip, time ,url, status, traffic}; 47 } 48 49 private String parseTraffic(String line) { 50 final String trim = line.substring(line.lastIndexOf("\"")+1).trim(); 51 String traffic = trim.split(" ")[1]; 52 return traffic; 53 } 54 private String parseStatus(String line) { 55 final String trim = line.substring(line.lastIndexOf("\"")+1).trim(); 56 String status = trim.split(" ")[0]; 57 return status; 58 } 59 private String parseURL(String line) { 60 final int first = line.indexOf("\""); 61 final int last = line.lastIndexOf("\""); 62 String url = line.substring(first+1, last); 63 return url; 64 } 65 private String parseTime(String line) { 66 final int first = line.indexOf("["); 67 final int last = line.indexOf("+0800]"); 68 String time = line.substring(first+1,last).trim(); 69 Date date = parseDateFormat(time); 70 return dateformat1.format(date); 71 } 72 private String parseIP(String line) { 73 String ip = line.split("- -")[0].trim(); 74 return ip; 75 } 76 }
输出结果:
1 源数据: 27.19.74.143 - - [30/04/2017:17:38:20 +0800] "GET /static/image/common/faq.gif HTTP/1.1" 200 1127 2 清洗结果数据: ip=27.19.74.143, time=20170430173820, url=GET /static/image/common/faq.gif HTTP/1.1, status=200, traffic=1127
再看mapreduce业务逻辑,在map中,我们需要拿出ip、time、url这三个属性的值,同时过滤掉静态资源日志。map的k1用默认的LongWritable就OK,v1不用说Text,k2、v2与k1、v1类型对应就行:
1 static class MyMapper extends Mapper<LongWritable, Text, LongWritable, Text>{ 2 LogParser logParser = new LogParser(); 3 Text v2 = new Text(); 4 @Override 5 protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, LongWritable, Text>.Context context) 6 throws IOException, InterruptedException { 7 final String[] parsed = logParser.parse(value.toString()); 8 9 //过滤掉静态信息 10 if(parsed[2].startsWith("GET /static/") || parsed[2].startsWith("GET /uc_server")){ 11 return; 12 } 13 //过掉开头的特定格式字符串 14 if(parsed[2].startsWith("GET /")){ 15 parsed[2] = parsed[2].substring("GET /".length()); 16 } 17 else if(parsed[2].startsWith("POST /")){ 18 parsed[2] = parsed[2].substring("POST /".length()); 19 } 20 //过滤结尾的特定格式字符串 21 if(parsed[2].endsWith(" HTTP/1.1")){ 22 parsed[2] = parsed[2].substring(0, parsed[2].length()-" HTTP/1.1".length()); 23 } 24 v2.set(parsed[0]+"\t"+parsed[1]+"\t"+parsed[2]); 25 context.write(key, v2); 26 }
reduce相对来说就比较简单了,我们只需再讲map的输出写到一个文件中就OK:
1 static class MyReducer extends Reducer<LongWritable, Text, Text, NullWritable>{ 2 @Override 3 protected void reduce(LongWritable arg0, Iterable<Text> arg1, 4 Reducer<LongWritable, Text, Text, NullWritable>.Context context) throws IOException, InterruptedException { 5 for (Text v2 : arg1) { 6 context.write(v2, NullWritable.get()); 7 } 8 } 9 }
最后,组装JOB:
1 public static void main(String[] args) throws IllegalArgumentException, IOException, ClassNotFoundException, InterruptedException { 2 Job job = Job.getInstance(new Configuration()); 3 job.setJarByClass(LogParser.class); 4 job.setMapperClass(MyMapper.class); 5 job.setMapOutputKeyClass(LongWritable.class); 6 job.setMapOutputValueClass(Text.class); 7 FileInputFormat.setInputPaths(job, new Path("/logs/20170430.log")); 8 job.setReducerClass(MyReducer.class); 9 job.setOutputKeyClass(Text.class); 10 job.setOutputValueClass(NullWritable.class); 11 FileOutputFormat.setOutputPath(job, new Path("/20170430")); 12 job.waitForCompletion(true); 13 }
mapreduce完成后就是运行job了:
1)打包,mapreduce程序为loger.jar
2)上传jar包。运行loger.jar hadoop jar loger.jar
运行结果:
hdfs多了20170430目录:
我们下载下来看看清洗后的数据是否符合要求:
日志数据的清洗到此就完成了,接下来我们要在此之上使用hive提取核心指标数据。
四、核心指标分析
1)构建一个外部分区表,sql脚本如下:
1 CREATE EXTERNAL TABLE sitelog(ip string, atime string, url string) PARTITIONED BY (logdate string) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' LOCATION '/20170430';
2)增加分区,sql脚本如下:
ALTER TABLE sitelog ADD PARTITION(logdate='20170430') LOCATION '/sitelog_cleaned/20170430';
3)统计每日PV,sql脚本如下:
1 CREATE TABLE sitelog_pv_20170430 AS SELECT COUNT(1) AS PV FROM sitelog WHERE logdate='20170430';
4)统计每日注册用户数,sql脚本如下:
1 CREATE TABLE sitelog_reguser_20170430 AS SELECT COUNT(1) AS REGUSER FROM sitelog WHERE logdate=20170430' AND INSTR(url,'member.php?mod=register')>0;
5)统计每日独立IP,sql脚本如下:
1 CREATE TABLE site_ip_20170430 AS SELECT COUNT(DISTINCT ip) AS IP FROM sitelog WHERE logdate='20170430';
6)统计每日跳出的用户数,sql脚本如下:
CREATE TABLE sitelog_jumper_20170430 AS SELECT COUNT(1) AS jumper FROM (SELECT COUNT(ip) AS times FROM sitelog WHERE logdate='20170430' GROUP BY ip HAVING times=1) e;
7)把每天统计的数据放入一张表中,sql脚本如下:
1 CREATE TABLE sitelog_20170430 AS SELECT '20170430', a.pv, b.reguser, c.ip, d.jumper FROM sitelog_pv_20170430 a JOIN sitelog_reguser_20170430 b ON 1=1 JOIN sitelog_ip_20170430 c ON 1=1 JOIN sitelog_jumper_20170430 d ON 1=1 ;
8)使用sqoop把数据导出到mysql中:
sqoop export --connect jdbc:mysql://hadoop02:3306/sitelog --username root --password root --table sitelog-result --fields-terminated-by '\001' --export-dir '/user/hive/warehouse/sitelog_20170430'
结果如下:
2017年4月30日日志分析结果:PV数为:169857;当日注册用户数:28;独立IP数:10411;跳出数:3749.
到此,一个简单的网站日志分析楼主就介绍完了,后面可视化的展示楼主就不写了,比较简单。相关代码地址:https://github.com/LJunChina/hadoop
大数据平台网站日志分析系统
1:项目技术架构图:2:流程图解析,整体流程如下: ETL即hive查询的sql; 但是,由于本案例的前提是处理海量数据,因而,流程中各环节所使用的技术则跟传统BI完全不同: 1) 数据采集:定制开发采集程序,或... 查看详情
flume监控hive日志文件(代码片段)
flume监控hive日志文件一:flume监控hive的日志1.1案例需求:1.实时监控某个日志文件,将数据收集到存储hdfs上面,此案例使用execsource,实时监控文件数据,使用MemoryChannel缓存数据,使用HDFSSink写入数据2.此案例实时监控hive日志文... 查看详情
基于hive的游戏日志数据可视化(hadoop,hive)
hive游戏日志数据可视化,五十万条数据存储在本地mysql中,通过sqoop导入到虚拟机中,然后通过hive处理好数据,最后通过sqoop将结果导出到本地mysql,利用ehcarts+springboot+vue将数据结果可视化出来,可... 查看详情
hive里loaddata执行日志怎么看
...,点击连接,2,展开数据库服务器下面的管理,SQLServer日志,3,双击当前可以打开日志文件查看器里面有所有的运行日志,4,点击任意一行,可以看见具体的信息,错误原因和时间,参考技术A用sqoop将数据库中的数据导入到hiv... 查看详情
#it明星不是梦#hive面试总结(代码片段)
...从形式来讲可以理解为文件夹,比如我们要收集某个大型网站的日志数据,一个网站每天的日志数据存在同一张表上,由于每天回生成大量的数据,导数数据表的内容过于巨大,在查询的时候权标扫描耗费的资源非常多。可以按... 查看详情
如何创建从 hive 表到关系数据库的数据管道
...间】:2013-02-2110:45:26【问题描述】:背景:我有一个包含日志信息的Hive表“日志”。该表每小时都会加载新的日志数据。我想对过去2天的日志进行一些快速分析,因此我想将过去48小时的数据提取到我的关系数据库中。为... 查看详情
sql使用hadoop,hive和hbase进行apache日志分析(代码片段)
谦先生的bug日志之hive启动权限问题
上海尚学堂谦先生的bug日志之hive启动权限问题这几天开始做新老集群的迁移,今天开始对hive的所有数据进行迁移,主要是表的元信息和表数据。表的元信息我们存在mysql中,跟hive的服务器并不在同一个服务器上,因此这块我们... 查看详情
使用hive重定向导出的数据文件中包含warn日志记录问题(代码片段)
...询发现,hive-f重定向导出的数据文件中带有如下两句WARN日志:WARN: The 查看详情
深入理解hive分区与分桶
...,在一定程度上提高查询效率。比如我们要收集某个大型网站的日志数据,一个网站每天的日志数据存在同一张表上,由于每天会生成大量的日志,导致数据表的内容巨大,在查询时进行全表扫描耗费的资源非常多。那其实这个... 查看详情
基础flinksqlhdfs到hive的逻辑处理一:通过正则获取日志数据(代码片段)
...:正则获取字段数据3.sql一、需求描述通过正则获取HDFSlog日志中指定字段的数据,并输出到HIVE表中。flink版本1.12.7。 二、实现1.主要连接器依赖<!--filesystem连接器--><dependency><groupId>org.apache.flink 查看详情
hive的网站
Hive简介 http://www.coin163.com/it/4435084950725826127 Hive的数据类型 https://cloud.tencent.com/developer/article/1165300 把HDFS上的数据导入到Hive中等操作 https://www.cnblogs.com/654wangzai321/p/9970321.html 查看详情
hive的数据案例统计网站的数据信息(代码片段)
根据hive的案例一增加需求一:增加案例需求:统计pv,uv,登录人数,游客人数,平均访问时长,二跳率,独立IP用一张表去处理1.1查看track_log的分区showpartitionstrack_log;1.2建立一张会话信息表(session):createtablesession_info(session_idstring,guids... 查看详情
大数据nifi(十九):实时json日志数据导入到hive(代码片段)
文章目录实时Json日志数据导入到Hive一、配置“TailFile”处理器1、创建“TailFile”处理器2、配置“PROPERTIES”二、配置“EvaluateJsonPath”处理器1、创建“EvaluateJsonPath”处理器2、配置“PROPERTIES”3、连接“TailFile”处理器和“EvaluateJs... 查看详情
hive日志
hive中日志分为两种: 1系统日志,记录hive运行情况,错误状态2job日志,记录hive中job执行的历史过程 系统日志存储位置:配置在hive/conf/hive-log4j.properties文件中记录了hive日志存储情况 默认存储信息:hive.root.logger=... 查看详情
如何获取基于 HIVE-SQOOP 的批处理作业的异常、错误和日志?
】如何获取基于HIVE-SQOOP的批处理作业的异常、错误和日志?【英文标题】:Howgetexception,error,logforHIVE-SQOOPbasedBatchJob?【发布时间】:2016-06-2705:08:02【问题描述】:我有6个数据节点和1个名称节点的Hadoop集群。我在HIVE中几乎没有(4)... 查看详情
hive查看日志
日志记录了程序运行的过程,是一种查找问题的利器。Hive中的日志分为两种1.系统日志,记录了hive的运行情况,错误状况。2.Job日志,记录了Hive中job的执行的历史过程。系统日志存储在什么地方呢?在hive/conf/hive-log4j.properties文... 查看详情
网站日志分析
http状态码: 200 正常返回; 301 重定向; 304 页面未修改; 404 无法访问; 500 服务器错误; 503 服务器不可用;日志分析: 1、软件分析 光年日志分析软件; 2、手工分... 查看详情