hive网站日志数据分析
一、说在前面的话
上一篇,楼主介绍了使用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中的源日志数据格式:
27.19.74.143 - - [30/4/2017:17:38:20 +0800] "GET /static/image/common/faq.gif HTTP/1.1" 200 1127
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协议、请求状态及当次流量。效果如下:
211.97.15.179 20170430173820 home.php?mod=misc&ac=sendmail&rand=1369906181
先写个日志解析类,测试是否能解析成功,我们再写mapreduce程序:
package mapreduce; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale; public class LogParser {
public static final SimpleDateFormat FORMAT = new SimpleDateFormat("d/MM/yyyy:HH:mm:ss", Locale.ENGLISH);
public static final SimpleDateFormat dateformat1=new SimpleDateFormat("yyyyMMddHHmmss");
public static void main(String[] args) throws ParseException {
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";
LogParser parser = new LogParser();
final String[] array = parser.parse(S1);
System.out.println("源数据: "+S1);
System.out.format("清洗结果数据: ip=%s, time=%s, url=%s, status=%s, traffic=%s", array[0], array[1], array[2], array[3], array[4]);
}
/**
* 解析英文时间字符串
* @param string
* @return
* @throws ParseException
*/
private Date parseDateFormat(String string){
Date parse = null;
try {
parse = FORMAT.parse(string);
} catch (ParseException e) {
e.printStackTrace();
}
return parse;
}
/**
* 解析日志的行记录
* @param line
* @return 数组含有5个元素,分别是ip、时间、url、状态、流量
*/
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 parseTraffic(String line) {
final String trim = line.substring(line.lastIndexOf("\"")+1).trim();
String traffic = trim.split(" ")[1];
return traffic;
}
private String parseStatus(String line) {
final String trim = line.substring(line.lastIndexOf("\"")+1).trim();
String status = trim.split(" ")[0];
return status;
}
private String parseURL(String line) {
final int first = line.indexOf("\"");
final int last = line.lastIndexOf("\"");
String url = line.substring(first+1, last);
return url;
}
private String parseTime(String line) {
final int first = line.indexOf("[");
final int last = line.indexOf("+0800]");
String time = line.substring(first+1,last).trim();
Date date = parseDateFormat(time);
return dateformat1.format(date);
}
private String parseIP(String line) {
String ip = line.split("- -")[0].trim();
return ip;
}
}
输出结果:
源数据: 27.19.74.143 - - [30/04/2017:17:38:20 +0800] "GET /static/image/common/faq.gif HTTP/1.1" 200 1127
清洗结果数据: 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类型对应就行:
static class MyMapper extends Mapper<LongWritable, Text, LongWritable, Text>{
LogParser logParser = new LogParser();
Text v2 = new Text();
@Override
protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, LongWritable, Text>.Context context)
throws IOException, InterruptedException {
final String[] parsed = logParser.parse(value.toString()); //过滤掉静态信息
if(parsed[2].startsWith("GET /static/") || parsed[2].startsWith("GET /uc_server")){
return;
}
//过掉开头的特定格式字符串
if(parsed[2].startsWith("GET /")){
parsed[2] = parsed[2].substring("GET /".length());
}
else if(parsed[2].startsWith("POST /")){
parsed[2] = parsed[2].substring("POST /".length());
}
//过滤结尾的特定格式字符串
if(parsed[2].endsWith(" HTTP/1.1")){
parsed[2] = parsed[2].substring(0, parsed[2].length()-" HTTP/1.1".length());
}
v2.set(parsed[0]+"\t"+parsed[1]+"\t"+parsed[2]);
context.write(key, v2);
}
reduce相对来说就比较简单了,我们只需再讲map的输出写到一个文件中就OK:
static class MyReducer extends Reducer<LongWritable, Text, Text, NullWritable>{
@Override
protected void reduce(LongWritable arg0, Iterable<Text> arg1,
Reducer<LongWritable, Text, Text, NullWritable>.Context context) throws IOException, InterruptedException {
for (Text v2 : arg1) {
context.write(v2, NullWritable.get());
}
}
}
最后,组装JOB:
public static void main(String[] args) throws IllegalArgumentException, IOException, ClassNotFoundException, InterruptedException {
Job job = Job.getInstance(new Configuration());
job.setJarByClass(LogParser.class);
job.setMapperClass(MyMapper.class);
job.setMapOutputKeyClass(LongWritable.class);
job.setMapOutputValueClass(Text.class);
FileInputFormat.setInputPaths(job, new Path("/logs/20170430.log"));
job.setReducerClass(MyReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(NullWritable.class);
FileOutputFormat.setOutputPath(job, new Path("/20170430"));
job.waitForCompletion(true);
}
mapreduce完成后就是运行job了:
1)打包,mapreduce程序为loger.jar
2)上传jar包。运行loger.jar hadoop jar loger.jar
运行结果:
hdfs多了20170430目录:
我们下载下来看看清洗后的数据是否符合要求:
日志数据的清洗到此就完成了,接下来我们要在此之上使用hive提取核心指标数据。
四、核心指标分析
1)构建一个外部分区表,sql脚本如下:
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='') LOCATION '/sitelog_cleaned/20170430';
3)统计每日PV,sql脚本如下:
CREATE TABLE sitelog_pv_20170430 AS SELECT COUNT(1) AS PV FROM sitelog WHERE logdate='';
4)统计每日注册用户数,sql脚本如下:
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脚本如下:
CREATE TABLE site_ip_20170430 AS SELECT COUNT(DISTINCT ip) AS IP FROM sitelog WHERE logdate='';
6)统计每日跳出的用户数,sql脚本如下:
CREATE TABLE sitelog_jumper_20170430 AS SELECT COUNT(1) AS jumper FROM (SELECT COUNT(ip) AS times FROM sitelog WHERE logdate='' GROUP BY ip HAVING times=1) e;
7)把每天统计的数据放入一张表中,sql脚本如下:
CREATE TABLE sitelog_20170430 AS SELECT '', 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
hive网站日志数据分析的更多相关文章
- 从0到1搭建基于Kafka、Flume和Hive的海量数据分析系统(一)数据收集应用
大数据时代,一大技术特征是对海量数据采集.存储和分析的多组件解决方案.而其中对来自于传感器.APP的SDK和各类互联网应用的原生日志数据的采集存储则是基本中的基本.本系列文章将从0到1,概述一下搭建基 ...
- Hadoop学习笔记—20.网站日志分析项目案例(一)项目介绍
网站日志分析项目案例(一)项目介绍:当前页面 网站日志分析项目案例(二)数据清洗:http://www.cnblogs.com/edisonchou/p/4458219.html 网站日志分析项目案例 ...
- Hadoop学习笔记—20.网站日志分析项目案例(二)数据清洗
网站日志分析项目案例(一)项目介绍:http://www.cnblogs.com/edisonchou/p/4449082.html 网站日志分析项目案例(二)数据清洗:当前页面 网站日志分析项目案例 ...
- Hadoop学习笔记—20.网站日志分析项目案例(三)统计分析
网站日志分析项目案例(一)项目介绍:http://www.cnblogs.com/edisonchou/p/4449082.html 网站日志分析项目案例(二)数据清洗:http://www.cnbl ...
- 基于hive的日志分析系统
转自 http://www.cppblog.com/koson/archive/2010/07/19/120773.html hive 简介 hive 是一个基于 ...
- hadoop日志数据分析开发步骤及代码
日志数据分析:1.背景1.1 hm论坛日志,数据分为两部分组成,原来是一个大文件,是56GB:以后每天生成一个文件,大约是150-200MB之间:1.2 日志格式是apache common日志格式: ...
- 基于日志数据分析以防御CC攻击的想法
1. What - 什么是CC攻击 CC攻击,即针对应用层HTTP协议的DDos攻击,攻击者在短时间内向目标服务器发送大量的HTTP请求,使得服务器会非常繁忙,资源消耗会增加:同时,如果请求中包含基于 ...
- 网站日志实时分析工具GoAccess使用
网站日志实时分析工具GoAccess使用 系统环境CentOS release 5.5 (Final) GoAccess是一款开源的网站日志实时分析工具. GoAccess 的工作方式就是读取和解析 ...
- 使用Nginx和Logstash以及kafka来实现网站日志采集的详细步骤和过程
使用Nginx和Logstash以及kafka来实现网站日志采集的详细步骤和过程 先列出来总体启动流程: (1)启动zookeeper集群(hadoop01.hadoop02和hadoop03这3台机 ...
随机推荐
- 高并发场景之RabbitMQ篇
上次我们介绍了在单机.集群下高并发场景可以选择的一些方案,传送门:高并发场景之一般解决方案 但是也发现了一些问题,比如集群下使用ConcurrentQueue或加锁都不能解决问题,后来采用Redis队 ...
- 20155231 2016-2017-2 《Java程序设计》第5周学习总结
# 20155231 2016-2017-2 <Java程序设计>第5周学习总结 教材学习内容总结 学习目标 理解异常架构 掌握try...catch...finally处理异常的方法 会 ...
- Java并发编程:Java线程池
转载自:http://www.cnblogs.com/dolphin0520/p/3932921.html 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题 ...
- 第三人称角色移动及自由移动视野(RigidBody实现)
重点:向量的运算.在获得水平及垂直方向的速度之后,将方向进行重设,让方向与视野同步(即:相机的方向与人物方向相同) 下面以一个实例来说明如何操作: 1.如图创建一个地形(Terrain),两个正方体( ...
- java 客户端发起http请求
package com.mall.core.utils.http; import org.apache.commons.lang.StringUtils; import org.apache.http ...
- 深入Callable及Runnable两个接口 获取线程返回结果
今天碰到一个需要获取线程返回结果的业务场景,所以了解到了Callable接口. 先来看下下面这个例子: public class ThreadTest { public static void mai ...
- Mybatis(四) 高级映射,一对一,一对多,多对多映射
天气甚好,怎能不学习? 一.单向和双向 包括一对一,一对多,多对多这三种情况,但是每一种又分为单向和双向,在hibernate中我们就详细解析过这单向和双向是啥意思,在这里,在重复一遍,就拿一对多这种 ...
- for xml path 如何将字段转换为xml的属性
for xml path 如何将字段作为xml的属性: 可在查询时 别名用 as '@..' 如'@value' 如下实例: SELECT A.GiftSetGUID AS '@value',A.Gi ...
- Azure IoT 技术研究系列3-设备到云、云到设备通信
上篇博文中我们将模拟设备注册到Azure IoT Hub中:我们得到了设备的唯一标识. Azure IoT 技术研究系列2-设备注册到Azure IoT Hub 本文中我们继续深入研究,设备到云.云到 ...
- MTK elian(smartlink)在WIN32下的实现
先说明一下调试技巧:该程序需无线网卡实现功能,由于PC端有可能是多网卡的(有线网卡.无线网卡.虚拟网卡),所以在发包的时候数据包不一定会从无线网卡出,lib库应该也没处理多网卡的选择吧.所以在调试的时 ...