热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

==Spark快速入门

Spark快速入门|JiZHANG’sBloghttp:shzhangji.comblog20141216spark-quick-startsc.textFile()用于生成一个R

Spark快速入门 | Ji ZHANG’s Blog
http://shzhangji.com/blog/2014/12/16/spark-quick-start/

sc.textFile()用于生成一个RDD,并声明该RDD指向的是/tmp/logs.txt文件。RDD可以暂时认为是一个列表,列表中的元素是一行行日志(因此是String类型)。

lines.map(f)表示对RDD中的每一个元素使用f函数来处理,并返回一个新的RDD。
line => line.split(“\t”)是一个匿名函数,又称为Lambda表达式、闭包等。它的作用和普通的函数是一样的,如这个匿名函数的参数是line(String类型),返回值是Array数组类型,因为String.split()函数返回的是数组。

需要注意的是,cache函数并不会立刻执行缓存操作,事实上map、filter等函数都不会立刻执行,而是在用户执行了一些特定操作后才会触发,比如first、count、reduce等。这两类操作分别称为Transformations和Actions。

之后对firstTenErrors的处理使用的是Scala集合类库中的方法,如map、foreach,和RDD提供的接口基本一致。所以说用Scala编写Spark程序是最自然的。

Apache Spark是新兴的一种快速通用的大规模数据处理引擎。它的优势有三个方面:
通用计算引擎 能够运行MapReduce、数据挖掘、图运算、流式计算、SQL等多种框架;
基于内存 数据可缓存在内存中,特别适用于需要迭代多次运算的场景;
与Hadoop集成 能够直接读写HDFS中的数据,并能运行在YARN之上。

Spark是用Scala语言编写的,所提供的API也很好地利用了这门语言的特性。它也可以使用Java和Python编写应用。本文将用Scala进行讲解。
安装Spark和SBT
从官网上下载编译好的压缩包,解压到一个文件夹中。下载时需注意对应的Hadoop版本,如要读写CDH4 HDFS中的数据,则应下载Pre-built for CDH4这个版本。
为了方便起见,可以将spark/bin添加到$PATH环境变量中:

1
2

export SPARK_HOME=/path/to/spark
export PATH=$PATH:$SPARK_HOME/bin

在练习例子时,我们还会用到SBT这个工具,它是用来编译打包Scala项目的。Linux下的安装过程比较简单:下载sbt-launch.jar到$HOME/bin目录;
新建$HOME/bin/sbt文件,权限设置为755,内容如下:

1
2

SBT_OPTS=”-Xms512M -Xmx1536M -Xss1M -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256M”
java $SBT_OPTS -jar dirname $0/sbt-launch.jar “$@”

日志分析示例
假设我们有如下格式的日志文件,保存在/tmp/logs.txt文件中:
1
2
3
4
5

2014-12-11 18:33:52 INFO Java some message
2014-12-11 18:34:33 INFO MySQL some message
2014-12-11 18:34:54 WARN Java some message
2014-12-11 18:35:25 WARN Nginx some message
2014-12-11 18:36:09 INFO Java some message

每条记录有四个字段,即时间、级别、应用、信息,使用制表符分隔。
Spark提供了一个交互式的命令行工具,可以直接执行Spark查询:
1
2
3
4
5
6
7
8
9

$ spark-shell
Welcome to

/ / ___ _____/ /__
\ / _ / _ `/ / ‘/
/
/ ./_,// //_\ version 1.1.0
/_/
Spark context available as sc.
scala>

加载并预览数据
1
2
3
4
5

scala> val lines = sc.textFile(“/tmp/logs.txt”)
lines: org.apache.spark.rdd.RDD[String] = /tmp/logs.txt MappedRDD[1] at textFile at :12

scala> lines.first()
res0: String = 2014-12-11 18:33:52 INFO Java some message

sc是一个SparkContext类型的变量,可以认为是Spark的入口,这个对象在spark-shell中已经自动创建了。
sc.textFile()用于生成一个RDD,并声明该RDD指向的是/tmp/logs.txt文件。RDD可以暂时认为是一个列表,列表中的元素是一行行日志(因此是String类型)。这里的路径也可以是HDFS上的文件,如hdfs://127.0.0.1:8020/user/hadoop/logs.txt。
lines.first()表示调用RDD提供的一个方法:first(),返回第一行数据。

解析日志
为了能对日志进行筛选,如只处理级别为ERROR的日志,我们需要将每行日志按制表符进行分割:
1
2
3
4
5

scala> val logs = lines.map(line => line.split(“\t”))
logs: org.apache.spark.rdd.RDD[Array[String]] = MappedRDD[2] at map at :14

scala> logs.first()
res1: Array[String] = Array(2014-12-11 18:33:52, INFO, Java, some message)

lines.map(f)表示对RDD中的每一个元素使用f函数来处理,并返回一个新的RDD。
line => line.split(“\t”)是一个匿名函数,又称为Lambda表达式、闭包等。它的作用和普通的函数是一样的,如这个匿名函数的参数是line(String类型),返回值是Array数组类型,因为String.split()函数返回的是数组。
同样使用first()方法来看这个RDD的首条记录,可以发现日志已经被拆分成四个元素了。

过滤并计数
我们想要统计错误日志的数量:
1
2
3
4
5
6
7
8

scala> val errors = logs.filter(log => log(1) == “ERROR”)
errors: org.apache.spark.rdd.RDD[Array[String]] = FilteredRDD[3] at filter at :16

scala> errors.first()
res2: Array[String] = Array(2014-12-11 18:39:42, ERROR, Java, some message)

scala> errors.count()
res3: LOng= 158

logs.filter(f)表示筛选出满足函数f的记录,其中函数f需要返回一个布尔值。
log(1) == “ERROR”表示获取每行日志的第二个元素(即日志级别),并判断是否等于ERROR。
errors.count()用于返回该RDD中的记录。

缓存
由于我们还会对错误日志做一些处理,为了加快速度,可以将错误日志缓存到内存中,从而省去解析和过滤的过程:
1

scala> errors.cache()

errors.cache()函数会告知Spark计算完成后将结果保存在内存中。所以说Spark是否缓存结果是需要用户手动触发的。在实际应用中,我们需要迭代处理的往往只是一部分数据,因此很适合放到内存里。
需要注意的是,cache函数并不会立刻执行缓存操作,事实上map、filter等函数都不会立刻执行,而是在用户执行了一些特定操作后才会触发,比如first、count、reduce等。这两类操作分别称为Transformations和Actions。
显示前10条记录
1
2
3
4
5
6
7

scala> val firstTenErrors = errors.take(10)
firstTenErrors: Array[Array[String]] = Array(Array(2014-12-11 18:39:42, ERROR, Java, some message), Array(2014-12-11 18:40:23, ERROR, Nginx, some message), …)

scala> firstTenErrors.map(log => log.mkString(“\t”)).foreach(line => println(line))
2014-12-11 18:39:42 ERROR Java some message
2014-12-11 18:40:23 ERROR Nginx some message
…

errors.take(n)方法可用于返回RDD前N条记录,它的返回值是一个数组。之后对firstTenErrors的处理使用的是Scala集合类库中的方法,如map、foreach,和RDD提供的接口基本一致。所以说用Scala编写Spark程序是最自然的。
按应用进行统计
我们想要知道错误日志中有几条Java、几条Nginx,这和常见的Wordcount思路是一样的。
1
2
3
4
5
6
7
8
9
10
11
12
13

scala> val apps = errors.map(log => (log(2), 1))
apps: org.apache.spark.rdd.RDD[(String, Int)] = MappedRDD[15] at map at :18

scala> apps.first()
res20: (String, Int) = (Java,1)

scala> val counts = apps.reduceByKey((a, b) => a + b)
counts: org.apache.spark.rdd.RDD[(String, Int)] = ShuffledRDD[17] at reduceByKey at :20

scala> counts.foreach(t => println(t))
(Java,58)
(Nginx,53)
(MySQL,47)

errors.map(log => (log(2), 1))用于将每条日志转换为键值对,键是应用(Java、Nginx等),值是1,如(“Java”, 1)
,这种数据结构在Scala中称为元组(Tuple),这里它有两个元素,因此称为二元组。
对于数据类型是二元组的RDD,Spark提供了额外的方法,reduceByKey(f)就是其中之一。它的作用是按键进行分组,然后对同一个键下的所有值使用f函数进行归约(reduce)。归约的过程是:使用列表中第一、第二个元素进行计算,然后用结果和第三元素进行计算,直至列表耗尽。如:
1
2

scala> Array(1, 2, 3, 4).reduce((a, b) => a + b)
res23: Int = 10

上述代码的计算过程即((1 + 2) + 3) + 4

counts.foreach(f)表示遍历RDD中的每条记录,并应用f函数。这里的f函数是一条打印语句(println)。
打包应用程序
为了让我们的日志分析程序能够在集群上运行,我们需要创建一个Scala项目。项目的大致结构是:
1
2
3
4
5
6
7
8
9

spark-sandbox
├── build.sbt
├── project
│ ├── build.properties
│ └── plugins.sbt
└── src
└── main
└── scala
└── LogMining.scala

你可以直接使用这个项目作为模板。下面说明一些关键部分:
配置依赖
build.sbt

1

libraryDependencies += “org.apache.spark” %% “spark-core” % “1.1.1”

程序内容
src/main/scala/LogMining.scala

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

import org.apache.spark.SparkContext
import org.apache.spark.SparkContext._
import org.apache.spark.SparkConf

object LogMining extends App {
val cOnf= new SparkConf().setAppName(“LogMining”)
val sc = new SparkContext(conf)
val inputFile = args(0)
val lines = sc.textFile(inputFile)
// 解析日志
val logs = lines.map(.split(“\t”))
val errors = logs.filter(
(1) == “ERROR”)
// 缓存错误日志
errors.cache()
// 统计错误日志记录数
println(errors.count())
// 获取前10条MySQL的错误日志
val mysqlErrors = errors.filter((2) == “MySQL”)
mysqlErrors.take(10).map(
mkString “\t”).foreach(println)
// 统计每个应用的错误日志数
val errorApps = errors.map(_(2) -> 1)
errorApps.countByKey().foreach(println)
}

打包运行
1
2
3

$ cd spark-sandbox
$ sbt package
$ spark-submit –class LogMining –master local target/scala-2.10/spark-sandbox_2.10-0.1.0.jar data/logs.txt

参考资料
Spark Programming Guide
Introduction to Spark Developer Training
Spark Runtime Internals


推荐阅读
  • Spring框架《一》简介
    Spring框架《一》1.Spring概述1.1简介1.2Spring模板二、IOC容器和Bean1.IOC和DI简介2.三种通过类型获取bean3.给bean的属性赋值3.1依赖 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • mac php错误日志配置方法及错误级别修改
    本文介绍了在mac环境下配置php错误日志的方法,包括修改php.ini文件和httpd.conf文件的操作步骤。同时还介绍了如何修改错误级别,以及相应的错误级别参考链接。 ... [详细]
  • 本文介绍了iPhone降频开关的位置和设置方法,以及解释了内存中的其他文件的含义和清理方法。同时提醒用户,在内存不足时系统会自动删除这些文件来腾出容量,因此不必过于担心。 ... [详细]
  • 超级简单加解密工具的方案和功能
    本文介绍了一个超级简单的加解密工具的方案和功能。该工具可以读取文件头,并根据特定长度进行加密,加密后将加密部分写入源文件。同时,该工具也支持解密操作。加密和解密过程是可逆的。本文还提到了一些相关的功能和使用方法,并给出了Python代码示例。 ... [详细]
  • 大数据Hadoop生态(20)MapReduce框架原理OutputFormat的开发笔记
    本文介绍了大数据Hadoop生态(20)MapReduce框架原理OutputFormat的开发笔记,包括outputFormat接口实现类、自定义outputFormat步骤和案例。案例中将包含nty的日志输出到nty.log文件,其他日志输出到other.log文件。同时提供了一些相关网址供参考。 ... [详细]
  • 本文介绍了在RHEL 7中的系统日志管理和网络管理。系统日志管理包括rsyslog和systemd-journal两种日志服务,分别介绍了它们的特点、配置文件和日志查询方式。网络管理主要介绍了使用nmcli命令查看和配置网络接口的方法,包括查看网卡信息、添加、修改和删除配置文件等操作。 ... [详细]
  • Hadoop源码解析1Hadoop工程包架构解析
    1 Hadoop中各工程包依赖简述   Google的核心竞争技术是它的计算平台。Google的大牛们用了下面5篇文章,介绍了它们的计算设施。   GoogleCluster:ht ... [详细]
  • 对于开源的东东,尤其是刚出来不久,我认为最好的学习方式就是能够看源代码和doc,測试它的样例为了方便查看源代码,关联导入源代 ... [详细]
  • 前言折腾了一段时间hadoop的部署管理,写下此系列博客记录一下。为了避免各位做部署这种重复性的劳动,我已经把部署的步骤写成脚本,各位只需要按着本文把脚本执行完,整个环境基本就部署 ... [详细]
  • 我们在之前的文章中已经初步介绍了Cloudera。hadoop基础----hadoop实战(零)-----hadoop的平台版本选择从版本选择这篇文章中我们了解到除了hadoop官方版本外很多 ... [详细]
  • MapReduce工作流程最详细解释
    MapReduce是我们再进行离线大数据处理的时候经常要使用的计算模型,MapReduce的计算过程被封装的很好,我们只用使用Map和Reduce函数,所以对其整体的计算过程不是太 ... [详细]
  • MapReduce 切片机制源码分析
     总体来说大概有以下2个大的步骤1.连接集群(yarnrunner或者是localjobrunner)2.submitter.submitJobInternal()在该方法中会创建 ... [详细]
  • Azkaban(三)Azkaban的使用
    界面介绍首页有四个菜单projects:最重要的部分,创建一个工程,所有flows将在工程中运行。scheduling:显示定时任务executing:显示当前运行的任务histo ... [详细]
author-avatar
国邮国旅刘峰
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有