spark学习笔记8 一个例子_Apache日志分析

需求

  • 统计每日 PV 和独立 IP
  • 统计每种不同的 HTTP 状态对应的访问数
  • 统计不同独立 IP 的访问量
  • 统计不同页面的访问量

基础知识准备

Apache日志位置

  • Windows下是: C:\Program Files\Apache Software Foundation\Apache2.2\logs\access.txt
  • Linux下是: /var/log/apache2/access.log

Apache日志文件格式

一条Apache记录,从左往右,大概是这个样子:

1.远程主机IP:表明访问网站的是谁 
2.空白(E-mail):为了避免用户的邮箱被垃圾邮件骚扰,第二项就用“-”取代了
3.空白(登录名):用于记录浏览者进行身份验证时提供的名字。
4.请求时间:用方括号包围,而且采用“公用日志格式”或者“标准英文格式”。 时间信息最后的“+0800”表示服务器所处时区位于UTC之后的8小时。
5.方法+资源+协议:服务器收到的是一个什么样的请求。该项信息的典型格式是“METHOD RESOURCE PROTOCOL”,即“方法 资源 协议”。
 METHOD: GET、POST、HEAD、……
RESOURCE: /、index.html、/default/index.php、……(请求的文件)
 PROTOCOL: HTTP+版本号
6.状态代码:请求是否成功,或者遇到了什么样的错误。大多数时候,这项值是200,它表示服务器已经成功地响应浏览器的请求,一切正常。
7.发送字节数:表示发送给客户端的总字节数。它告诉我们传输是否被打断(该数值是否和文件的大小相同)。把日志记录中的这些值加起来就可以得知服务器在一天、一周或者一月内发送了多少数据
8、url以及客户端的详细信息,比如操作系统、浏览器等等

另外,经过查找,也有说法说,第二项和第三项分别是客户端记录和浏览者记录。
以及,第4项请求时间里面的“标准格式”是有:日期、时间、地区三种信息的。

例如这条Apache日志记录

180.76.15.161 - - [06/Dec/2014:06:49:26 +0800] "GET / HTTP/1.1" 200 10604 "-" "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)"

就,非常明显,每一项都是能够对应得上的,哪个位置都是什么。

正则表达式


正则表达式手册
菜鸟工具 正则表达式在线测试

PV

pv(Page View)单指访问量,每打开一次页面PV计数+1,刷新页面也是。和UV是不一样的
UV是访问数(Unique Visitor)指独立访客访问数,一台电脑终端为一个访客。

实现

下载资料

自己电脑上的Apache日志基本没有什么,就算做实验搭建过web服务器,也是仅限于局域网,数据量比较少。这个实验选取的数据来源是:

http://labfile.oss.aliyuncs.com/courses/456/access.log

可以用wget命令下载到当前目录下。

嗯,一兆多一点的文本文件。

解析记录生成新RDD

这个正则表达式是对除了客户端详细信息以外的前7项内容做解析的,需求里面要每天的ip,所以需要分出来ip和时间。然后,还要求了不同http状态的访问数和页面访问量,所以还需要有HTTP状态码和URL。下面这个正则表达式,可以用来过滤掉不能够解析的日志记录,并解析有需要的信息的日志记录。下面这句scala让正则表达式的字符串调用了r这个方法从而创建了一个Regex对象也就是正则表达式对象

val logPattern = """^(\S+) (\S+) (\S+) \[([\w/]+)([\w:/]+)\s([+\-]\d{4})\] "(\S+) (\S+) (\S+)" (\d{3}) (\d+)""".r

然后使用这个正则表达式来实现两个函数,分别用来实现上面的,过滤不能解析的日志记录和解析需要的信息的功能。
这个是过滤不能够识别的信息的:

def filterWithParse(s: String) = {
    logPattern.findFirstIn(s) match {
        case Some(logPattern(_*)) => true
        case _ => false
    }
}

根据我对scala的浅显了解,这个函数起作用的就是Some类,Some类是继承了Option类的一个类,主要就是用来判断这个是不是none的。
能够匹配,或者说能用的记录就是true否则就是false
下一个函数是用来解析日志,并且获取所需要的的信息的。

def parseLog(s: String) = {
    val m = logPattern.findAllIn(s)
    if(m.hasNext){
        val clientIP = m.group(1).toString
        val requestDate = m.group(4).toString
        val requestURL = m.group(8).toString
        val status = m.group(10).toString
        (clientIP, requestDate, requestURL, status)
    } else {
        ("null", "null", "null", "null")
        // 为了便于分析数据,此处用一个内容为“null”的字符串来统计无效值
    }
}

然后,筛选的传给filter,filter的结果调用map,而map的参数就是parseLog这个分析函数,最后生成一个新的RDD

val logRDDv1 = logRDD.filter(filterWithParse).map(parseLog)

这个logRDDv1就是后面做分析,然后实现最开始的要求的基础。

在新RDD基础上做统计

pv

新RDD里面一共有5122条记录

题目要求是根据日期统计pv数量的,而刚才新生成RDD的时候,日期是放在了RDD的第二列或者说每一条记录的第二项。
然后,我还需要知道的是,在scala的元组里面计数是从1开始的不是0。
利用这些,生成一个新的键值对RDD: logRDDv2,里面的键是日期,每个键对应的值是加和加出来的数量。

然后,按时间排序,保存

每日ip

生成一个,键是日期,值是ip的键值对rdd

val logRDDv3 = logRDDv1.map(x => (x._2, x._1))

调用distinct给这个rDD去重,再给去完重的RDD统计每日独立的ip访问数,因为distinct完成之后,每一行就是说这一天有这个ip访问,然后同一天的行数就是这一天访问服务器的独立ip数。
所以就按值相加生成一个新的键值对RDD喽。

val logRDDv4 = logRDDv3.distinct()
val logRDDv5 = logRDDv4.map(x => (x._1, 1)).reduceByKey(_ + _)
val DIP = logRDDv5.collect()

每种HTTP的状态数

下面就基本是和统计每日独立ip和pv差不多的操作了
比如这个统计每种HTTP的状态数,就是按每一行的http状态的那个属性生成一个键值对rdd然后就按照相同的键相加,就得到了每种http的状态数。和Wordcount那个例子其实区别不大。

val logRDDv6 = logRDDv1.map(x => (x._4, 1)).reduceByKey(_ + _)
val StatusPV = logRDDv6.sortByKey().collect()

不同的独立ip访问量

嗯。还是一样的操作

val logRDDv7 = logRDDv1.map(x => (x._1, 1)).reduceByKey(_ + _)
val IPPV = logRDDv7.sortBy(x => x._2, false).collect()

这里的话,我需要注意一下这个sortBy,因为以前我觉得在scala里面排序一般都是sortByKey,但是其实sortBy就可以做按键值对的“值”来排序。
sortBy函数的第二个参数传入false的意思让它降序排序。其实还有第三个参数,用来决定排序完之后的RDD的分区个数。详见参考资料。

不同页面的访问量

这个如果没有教程的话,我应该会直接像上面那样做完了就拉到了
就这样

val logRDDv8 = logRDDv1.map(x => (x._3, 1)).reduceByKey(_ + _)
val PagePV = logRDDv8.sortBy(x => x._2, false).collect()


但是,就像教程说的:

通过查看 PagePV 我们发现有大量的 js 文件的访问,这不是我们需要的内容,

然后,教程提供了一个很巧妙地去除有问题的页面访问的办法

一看,这不就是上次学的那个停词表么,只不过这个停的不是词,是文件的后缀名
就,属于这个列表的就不要,不是这个列表里面的就统计,然后根据这个生成新的rdd,再用新的rdd做上面统计ip那些操作。

参考资料

Scala字符串中的查找模式
正则表达式手册
菜鸟工具 正则表达式在线测试
class Some
sortByKey和sortBy函数详解

posted @ 2020-01-12 11:55  ltl0501  阅读(397)  评论(0编辑  收藏  举报