日志信息如下所示:

1.1.1.1 - - [21/Jul/2014:10:00:00 -0800] "GET /majihua/article/284234 HTTP/1.1" 200 1234

1.1.1.1 - - [21/Jul/2014:10:00:00 -0800] "GET /majihua/article/284234 HTTP/1.1" 200 2000

1.1.1.1 - - [21/Jul/2014:10:00:00 -0800] "GET /majihua/article/284234 HTTP/1.1" 401 100

从左到右,各字段分别表示的意思分别是Client请求IP地址、Client(这里为-)、用户名(这里为-)、请求时间、请求方式(这里是GET)、请求的资源、传输协议(这里是HTTP/1.1)、HTTP响应码(200表示正常响应)、响应内容的大小

Spark处理:

1.代码

类1:LogAnalyzer

import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.Function2;
import scala.Tuple2;
import java.io.Serializable;
import java.util.Comparator;
import java.util.List;
/**
* Main Class
*/
public class LogAnalyzer {
public static void main(String[] args) {
//local D:/my.log
if (args.length < 1) {
System.out.println("必须输入程序运行模式名称和要处理的日志文件路径!");
System.exit(-1);
} // 通过SparkConf来创建Spark程序运行的上下文,一个SparkContext就相当于运行的一个APP
// AppName是程序的名字,Master是运行模式,local为本地单线程模式,
// Master最好不要写死到程序中,关于Spark部署模式,详见注解1
SparkConf conf = new SparkConf().setAppName("Log Analyzer").setMaster(args[0]);
JavaSparkContext sc = new JavaSparkContext(conf); //将日志文件读取到RDD中
String logFile = args[1];
JavaRDD<String> logLines = sc.textFile(logFile); //由于textFile是以行为最小单位进行操作的,所以这里是把每一行日志信息存储到一个ApacheAccessLog类中
//ApacheAccessLog::parseFromLogLine是JDK8新增的类调用方法的新特性,感觉挺酷的
//我们使用accessLogs RDD,主要用于(1)统计响应内容均值、最小值、最大值(2)响应码的种类及个数
//(3)请求次数超过10次的Client IP地址(4)请求的资源Top10
// 因为使用这个accessLogs RDD 4次,所以我们调用cache方法缓存到内存中
JavaRDD<ApacheAccessLog> accessLogs =
logLines.map(ApacheAccessLog::parseFromLogLine).cache(); System.out.println("日志处理结果如下所示:"); //(1)统计响应内容均值、最小值、最大值
//对于每个类ApacheAccessLog调用getContentSize方法
JavaRDD<Long> contentSizes =
accessLogs.map(ApacheAccessLog::getContentSize).cache();
System.out.println(String.format("(1)响应内容大小平均值: %s, 最小值: %s, 最大值: %s",
contentSizes.reduce(SUM_REDUCER) / contentSizes.count(),
contentSizes.min(Comparator.naturalOrder()),
contentSizes.max(Comparator.naturalOrder()))); // (2)响应码的种类及个数
List<Tuple2<Integer, Long>> responseCodeToCount =
accessLogs.mapToPair(log -> new Tuple2<>(log.getResponseCode(), 1L))
.reduceByKey(SUM_REDUCER)
.take(100);
System.out.println(String.format("(2)响应码种类及个数: %s", responseCodeToCount)); // (3)请求次数超过10次的Client IP地址
List<String> ipAddresses =
accessLogs.mapToPair(log -> new Tuple2<>(log.getIpAddress(), 1L))
.reduceByKey(SUM_REDUCER)
.filter(tuple -> tuple._2() > 10)
.map(Tuple2::_1)
.take(100);
System.out.println(String.format("(3)请求次数超过10次的IP地址: %s", ipAddresses)); // (4)请求的资源Top10
List<Tuple2<String, Long>> topEndpoints = accessLogs
.mapToPair(log -> new Tuple2<>(log.getEndpoint(), 1L))
.reduceByKey(SUM_REDUCER)
.top(10, new ValueComparator<>(Comparator.<Long>naturalOrder()));
System.out.println(String.format("(4)请求的资源Top10: %s", topEndpoints)); // 停止应用程序
sc.stop();
} //定义一个累加功能的函数
private static Function2<Long, Long, Long> SUM_REDUCER = (a, b) -> a + b;
//定义一个类比较器
private static class ValueComparator<K, V>
implements Comparator<Tuple2<K, V>>, Serializable {
private Comparator<V> comparator; public ValueComparator(Comparator<V> comparator) {
this.comparator = comparator;
} @Override
public int compare(Tuple2<K, V> o1, Tuple2<K, V> o2) {
return comparator.compare(o1._2(), o2._2());
}
}
}

类2:ApacheAccessLog

/**
* 每个类代表日志文件的每一行
*/
public class ApacheAccessLog implements Serializable {
private static final Logger logger = Logger.getLogger("Access"); private String ipAddress;
private String clientIdentd;
private String userID;
private String dateTimeString;
private String method;
private String endpoint;
private String protocol;
private int responseCode;
private long contentSize; private ApacheAccessLog(String ipAddress, String clientIdentd, String userID,
String dateTime, String method, String endpoint,
String protocol, String responseCode,
String contentSize) {
this.ipAddress = ipAddress;
this.clientIdentd = clientIdentd;
this.userID = userID;
this.dateTimeString = dateTime;
this.method = method;
this.endpoint = endpoint;
this.protocol = protocol;
this.responseCode = Integer.parseInt(responseCode);
this.contentSize = Long.parseLong(contentSize);
} public String getIpAddress() {
return ipAddress;
} public String getClientIdentd() {
return clientIdentd;
} public String getUserID() {
return userID;
} public String getDateTimeString() {
return dateTimeString;
} public String getMethod() {
return method;
} public String getEndpoint() {
return endpoint;
} public String getProtocol() {
return protocol;
} public int getResponseCode() {
return responseCode;
} public long getContentSize() {
return contentSize;
} public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
} public void setClientIdentd(String clientIdentd) {
this.clientIdentd = clientIdentd;
} public void setUserID(String userID) {
this.userID = userID;
} public void setDateTimeString(String dateTimeString) {
this.dateTimeString = dateTimeString;
} public void setMethod(String method) {
this.method = method;
} public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
} public void setProtocol(String protocol) {
this.protocol = protocol;
} public void setResponseCode(int responseCode) {
this.responseCode = responseCode;
} public void setContentSize(long contentSize) {
this.contentSize = contentSize;
} // 日志文件示例:
// 127.0.0.1 - - [21/Jul/2014:9:55:27 -0800] "GET /home.html HTTP/1.1" 200 2048
private static final String LOG_ENTRY_PATTERN =
// Client请求IP地址、Client(这里为-)、用户名(这里为-)、请求时间、请求方式(这里是GET)、请求的资源、传输协议(这里是HTTP/1.1)、HTTP响应码(200表示正常响应)、响应内容的大小
"^(\\S+) (\\S+) (\\S+) \\[([\\w:/]+\\s[+\\-]\\d{4})\\] \"(\\S+) (\\S+) (\\S+)\" (\\d{3}) (\\d+)";
private static final Pattern PATTERN = Pattern.compile(LOG_ENTRY_PATTERN); public static ApacheAccessLog parseFromLogLine(String logline) {
Matcher m = PATTERN.matcher(logline);
if (!m.find()) {
logger.log(Level.ALL, "不能解析日志文件" + logline);
throw new RuntimeException("解析日志文件出错");
} return new ApacheAccessLog(m.group(1), m.group(2), m.group(3), m.group(4),
m.group(5), m.group(6), m.group(7), m.group(8), m.group(9));
} @Override public String toString() {
return String.format("%s %s %s [%s] \"%s %s %s\" %s %s",
ipAddress, clientIdentd, userID, dateTimeString, method, endpoint,
protocol, responseCode, contentSize);
}
}

运行结果:

2.注解

注解1:Spark部署模式分为单机和集群模式

2.1单机模式,一般适用于本地调试程序

这个比较好理解,local代表一个线程运行该程序,local[n]代表n个线程运行该程序

使用方法I)在程序中通过.setMaster(“local”)直接写死II)jar运行时通过--master=local

2.2集群模式

根据Driver程序的位置,集群模式分为Client和Cluster两种,根据所使用的资源管理器集群模式又分为Standalone、YARN、Mesos、Amazon EC2

a)Standalone Spark自己实现的一个简单的集群运行模式

启动命令:./bin/spark-submit --master=spark://IP:PORT ...

b)YARN模式

Yarn-cluster启动命令:./bin/spark-submit  --master yarn-cluster ...

Yarn-client启动命令:./bin/spark-submit  --master yarn-client ...

c)Mesos模式

启动命令:./bin/spark-submit  --master mesos://host:5050 ...

【原】日志处理-Spark的更多相关文章

  1. 【原】Learning Spark (Python版) 学习笔记(三)----工作原理、调优与Spark SQL

    周末的任务是更新Learning Spark系列第三篇,以为自己写不完了,但为了改正拖延症,还是得完成给自己定的任务啊 = =.这三章主要讲Spark的运行过程(本地+集群),性能调优以及Spark ...

  2. 【原】Learning Spark (Python版) 学习笔记(一)----RDD 基本概念与命令

    <Learning Spark>这本书算是Spark入门的必读书了,中文版是<Spark快速大数据分析>,不过豆瓣书评很有意思的是,英文原版评分7.4,评论都说入门而已深入不足 ...

  3. 【原】Learning Spark (Python版) 学习笔记(二)----键值对、数据读取与保存、共享特性

    本来应该上周更新的,结果碰上五一,懒癌发作,就推迟了 = =.以后还是要按时完成任务.废话不多说,第四章-第六章主要讲了三个内容:键值对.数据读取与保存与Spark的两个共享特性(累加器和广播变量). ...

  4. 【原】Learning Spark (Python版) 学习笔记(四)----Spark Sreaming与MLlib机器学习

    本来这篇是准备5.15更的,但是上周一直在忙签证和工作的事,没时间就推迟了,现在终于有时间来写写Learning Spark最后一部分内容了. 第10-11 章主要讲的是Spark Streaming ...

  5. [原][粒子特效][spark]调节器modifier

    深入浅出spark粒子特效连接:https://www.cnblogs.com/lyggqm/p/9956344.html group添加modifier的方式: modifier An abstra ...

  6. [原][粒子特效][spark]事件action

    深入浅出spark粒子特效连接:https://www.cnblogs.com/lyggqm/p/9956344.html group调用action的地方: 可以看到使用action的可以是出生一次 ...

  7. [原][粒子特效][spark]插值器interpolator

    深入浅出spark粒子特效连接:https://www.cnblogs.com/lyggqm/p/9956344.html 插值器是体现粒子生命周期变化的功能 group使用到插值器的方式: 可以看到 ...

  8. [原][粒子特效][spark]粒子系统system、主节点group、渲染器render

    深入浅出spark粒子特效连接:https://www.cnblogs.com/lyggqm/p/9956344.html system: A class defining a complete sy ...

  9. [原][粒子特效][spark]发射器emitter

    深入浅出spark粒子特效连接:https://www.cnblogs.com/lyggqm/p/9956344.html group添加emitter的方式: eimtter: 上图是spark源码 ...

随机推荐

  1. C#实现登录窗口(不用隐藏)

    C#登录窗口的实现,特点就是不用隐藏,感兴趣的朋友不要错过 (1).在程序入口处,打开登录窗口 复制代码代码如下: static void Main()  {  Application.EnableV ...

  2. 解决MySQL查询不区分大小写

    需要设置collate(校对) . collate规则: *_bin: 表示的是binary case sensitive collation,也就是说是区分大小写的 *_cs: case sensi ...

  3. 001.XE3添加TPerlRegEx

    TPerlRegEx 官方下载地址:http://www.regular-expressions.info/download/TPerlRegEx.zip 下载解压,打开pcre.pas文件可看到,直 ...

  4. hdu 2079 选课时间

    hdu 2079 选课时间 题意:选的学分总和为n,并且学分为a的课有b种,总共有K(1<=k<=8)种学分不同的课,并且要选的学分最多为40:问选课方案有多少种?(学分相同的课即认为相同 ...

  5. hive 中的Sort By、 Order By、Cluster By、Distribute By 区别

    Order by: order by 会对输入做全局排序,因此只有一个reducer(多个reducer无法保证全局有序)只有一个reducer,会导致当输入规模较大时,需要较长的计算时间.在hive ...

  6. Excel skills (2) -- 自动调整行宽列高

    快捷键: 行宽,Alt + O + R + A; 列高,Alt + O + C + A;

  7. Portlet 通信过程详解

    Portlet 通信过程详解 在 Portal 的开发过程中,Theme 与 portlet 之间的通信,以及 portlet 之间的通信是开发人员常常遇到的问题.通常 Portlet 之间需要能够互 ...

  8. 【win8技巧】应用商店里面如何搜索应用app

    win8应用商店搜索app软件的技巧 1.组合键 WIN+C 打开屏幕最右边磁条 2.点击搜索,输入你想搜的软件名称,里面会列出你已经安装的app或者你点击下面的应用商店选项,就可以搜索互联网上应用商 ...

  9. FZU 2150 Fire Game(BFS)

    点我看题目 题意 :就是有两个熊孩子要把一个正方形上的草都给烧掉,他俩同时放火烧,烧第一块的时候是不花时间的,每一块着火的都可以在下一秒烧向上下左右四块#代表草地,.代表着不能烧的.问你最少花多少时间 ...

  10. php smarty insert用法

    insert用于模板中. 用法:{insert name="method_name"} 此时会寻找php文件中方法名为:insert_method_name的函数, 将其返回值作为 ...