* SparkCore基础(一)

学习Spark,首先要熟悉Scala,当然你说你会Python或者Java能不能玩Spark?能!但是不推荐,首推Scala,因为Scala非常便捷,而且Scala有非常好的交互式编程体验(当然了,在这里,Python也不差)。其次呢,我们要对Hadoop的MapReduce要是有一定的了解。不然,学习起来,是会稍微费点功夫。好,不扯这么多了,相关的故事啊,疑问啊可以评论留言询问或者百度查询,我们现在直接进入正题。

 
 

Spark特征简述

* Spark是什么

官方描述:Spark is a fast and general engine for large-scale data processing

** Spark是一个快速的,通用的,大数据规模的运算引擎。这是一个非常精准的描述。

** Spark是基于MapReducer实现的通用的分布式计算框架,所以它继承了MapReduce的优点,同时还支持将Job运算任务产生的中间结果和最终结果保存在内存中。

* Spark优势

** Spark的中间数据放到内存中,对于迭代运算效率更高

** 运算速度奇快

** 更灵活的数据操作,比如:map, filter, flatMap, sample, groupByKey, reduceByKey, union, join, cogroup, mapValues, sort,partionBy等等

* Spark不适合做什么

** 不适合做增量变化的应用模型

* Spark支持语言

Java、Scala、Python

* 适用场景讨论

** 适用于需要多次操作特定数据集的应用场合。需要反复操作的次数越多,所需读取的数据量越大,受益越大,数据量小但是计算密集度较大的场*合,受益就相对较小。

Spark下载

一般情况下,我们使用spark之前,都需要下载源码,然后根据自己的集群环境(也就是Hadoop版本)进行编译,然后再安装使用。

Spark下载:

http://spark.apache.org/downloads.html

打开页面后,做出如下选择,即可开始下载源码

 
在这里我们使用1.6.1的源码

Spark编译

在此我们简单介绍两种方式:

** SBT编译

这是一个类似Maven的仓库,基于Scala

** Maven编译

命令:

 
 

** make-distribution.sh编译

修改源码根目录下的make-distribution.sh文件,修改内容如图:

 
 

依次为:配置Spark版本,Scala版本,Hadoop版本,是否支持Hive,1为支持

配置镜像:注意,如果编译的是原版,请添加此镜像,如果编译的是CDH版本的,请注意去掉此镜像。

 
 

配置域名解析服务器:

$ sudo vi /etc/resolv.conf,配置如下:

nameserver 8.8.8.8

nameserver 8.8.4.4

最后执行命令:

 
注意要支持yarn和hive

世界充满爱之编译好的Spark传送门(分别包含包含Apache和CDH版本的):

链接:http://pan.baidu.com/s/1eRBJtjs 密码:t03u

Spark运行模式

** Local

即本地模式

** Standalone

即Spark自带的集群模式,分为Master节点和Worker节点,顾名思义,一个管理者,多个干活的。:)

** Yarn

国内相当主流的一种运行部署模式,只是目前Yarn分配的Container是不能够动态伸缩的,后续可能会考虑支持。

** Mesos

Spark在出生的时候就考虑支持该框架,很灵活,但国内使用似乎不多,感兴趣请自行研究之。

Spark安装部署

将Spark解压出来,然后到conf目录下,自己将template文件拷贝出文后提到的文件进行配置即可,在之前的章节我们已经提到过很多次,此步骤想必应该非常熟练了,不再赘述了。

Local模式:

spark-env.sh 文件配置如下:

 
 

Spark测试案例之Local模式

在案例开始前,请确保你的HDFS是可用的,并且spark-shell在active的NameNode节点上运行。此刻建议你已经熟知Hadoop中MapReduce的编写过程以及运行原理。

案例一:基于本地模式的WordCount,words.txt中的内容:

 
 

Step1、进入spark根目录使用$ bin/spark-shell命令启动spark,如下图:

 
 

Step2、读取/input/words.txt文件,尝试检查一下words.txt文件有多少行数据,操作如下:

scala> val rdd = sc.textFile("/input/words.txt")

 
 

scala> rdd.count

 
当然了,统计词频,这个步骤可以省略,在此只是想验证一下自己读取到的数据有没有问题

好,大家可以看到,有3行数据,每一行都有若干英文单词。那么这里面涉及到几个问题需要拿出来讨论一下:

1、什么是rdd?

RDD is a fault-tolerant collection of elements that can be operated on in parallel,RDD是弹性分布式数据集,全称Resilient Distributed Datasets,具有分布式,高容错性等特点,在这里,刚开始接触的话,你可暂且理解为一个集合就可以了,一个数据集合。

2、什么是sc?

sc的全称是SparkContext,即Spark的上下文对象,这个理解可以类比于在Hadoop阶段我们在MapReduce中接触到的Context,不管是读取文件还是其他数据操作,都依赖于SparkContext的实例化。在这里,sc即一个实例化好的SparkContext对象。

我们通过sc.textFile方法读取到HDFS系统中存放的words.txt文件信息,该方法返回一个RDD对象,之后我们通过rdd对象调用count方法,来查看读取到的文件中数据有多少行。

Step3、利用得到的rdd对象进行数据的拆分,即,每一个单词都拆分成一个RDD对象,比如类似这样的理解:RDD<String> rdd = new RDD("hadoop");那么使用scala在spark中如何做呢?请看:

scala> val wordRdd = rdd.flatMap(line => line.split(" "))

 
 

然后我们使用wordRdd显示一下第一个单词看一看:

scala> wordRdd.first

 
 

Step4、将分割出来的每一个单词做Map映射

scala> val mapRdd = wordRdd.map(word => (word, 1))

 
 

这是scala的高阶函数,注意不理解请重新复习Scala语言。该语句的意思是:将wordRdd中存放的单词映射为一个tuple元组,元组中有两个元素,第一个元素为单词,第二个元素为当前单词本次的个数,固定为1,这个1就像Hadoop阶段中Map的LongWritable一样,这个word就像Text一样。

Step5、这一步要做的就是讲map映射出来的数据集进行reduce运算

scala> val reduceRdd = mapRdd.reduceByKey((x, y) => x + y)

 
 

该行代码的意思是将某一个单词的好多个1(当然如果进行Combine操作了,也许可能不是多个1,如果你无法理解我这一句在说什么,请继续前进,然后重新复习Hadoop的MapReduce相关知识点)进行相加运算。

Step6、查看一下结果

scala> reduceRdd.collect

 
 

显示出来了,而且执行过程非常的迅速,你懂得。

当然了,以上的操作,完全可以使用一句话来实现,并且代码的体现形式可以非常骚气,如:

scala> sc.textFile("/input/words.txt").flatMap(_.split(" ")).map((_, 1)).reduceByKey(_+_).collect

 
 

Step7、当然了结果也可以输出到HDFS系统当中,比如:

scala> reduceRdd.saveAsTextFile("/output/spark/test01")

案例二:基于案例一,进行二次排序,即,将统计出的词频结果按照降序或者升序排列

sc.textFile("/input/words.txt")

.flatMap(_.split(" "))

.map((_, 1))

.reduceByKey(_ + _)

.map(x => (x._2, x._1))

.sortByKey()

.map(x => (x._2, x._1))

.collect

Step1、得到案例一的统计好的词频结果,然后做一个map映射,将单词和单词出现的次数颠倒过来,也就是说,(hadoop, 1)变成(1, hadoop),这样做的原因是因为OrderedRDDFunctions类中有一个方法叫做:sortByKey,意思是按照Key的大小进行排序,默认参数是升序,如图:

 
 

为了使用该方法,我们这么做:

上一个案例,我们得到:

val reduce = sc.textFile("/input/words.txt").flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _)

然后:

val reverseRdd = reduce.map(x => (x._2, x._1))

然后我们看一眼这个RDD集合:

 
 

Step2、直接使用sortByKey进行默认排序

val sortRdd = reverseRdd.sortByKey()

Step3、排序结束你不得给人家再反转回来?所以:

sortRdd.map(x => (x._2, x._1)).collect,如图:

 
 

当然了,以上分解步骤一气呵成最爽快:

sc.textFile("/input/words.txt")

.flatMap(_.split(" "))

.map((_, 1))

.reduceByKey(_ + _)

.map(x => (x._2, x._1))

.sortByKey()

.map(x => (x._2, x._1))

.collect

Step4、当然了,sortByKey方法也可以实现倒序,如:

sc.textFile("/input/words.txt")

.flatMap(_.split(" "))

.map((_, 1))

.reduceByKey(_ + _)

.map(x => (x._2, x._1))

.sortByKey(false)

.map(x => (x._2, x._1))

.collect

Step5、二次排序还可以使用top

top源码:

 
 

这是一个柯里化的函数,top命令是查看前多少条数据,如图可见,在查看之时,元素也是排序好的

比如:

sc.textFile("/input/words.txt")

.flatMap(_.split(" "))

.map((_, 1))

.reduceByKey(_ + _)

.map(x => (x._2, x._1))

.top(12)

输出如图:

 
 

Spark运行模式之Standalone

配置:spark-env.sh

 

 
 

Master节点:SPARK_MASTER_IP=z01

Master节点端口号:SPARK_MASTER_PORT=7077

Master WebUI端口号:SPARK_MASTER_WEBUI_PORT=8080

Worker节点可用CPU核心数:SPARK_WORKER_CORES=2

Worker可用内存:SPARK_WORKER_MEMORY=2g

Worker端口号:SPARK_WORKER_PORT=7078

Worker WebUI端口号:SPARK_WORKER_WEBUI_PORT=8081

允许在每台机器上开启几个Worker进程,默认为1个SPARK_WORKER_INSTANCES=1

配置:slaves

即配置允许哪几台机器当做Woker节点

 
 

以上配置完成后,scp到其他集群节点

启动:

Master

$ sbin/start-master.sh

Worker

$ sbin/start-slaves.sh

完成后通过z01:8080端口访问即可如图所示:

 
 

也可以JPS看一下进程:

 
 

在Standalone上运行Spark

首先,查看一下spark的帮助文档来引导该怎么做:

$ bin/spark-shell --help

 
 

注意红框内的内容,那么接下来,我们应该知道怎么让spark运行在standalone上了:

$ bin/spark-shell --master spark://z01:7077

如图:注意红框内容

 
 

尖叫提示:如果直接不加参数的使用spark-shell方式启动,则还是在本地模式(Local)启动的。

Spark测试案例之Standalone模式

案例一:跑一个一气呵成的WordCount

scala> sc.textFile("/input/words.txt").flatMap(_.split(" ")).map((_, 1)).reduceByKey(_+_).collect

WEBUI,http://192.168.122.200:4040/jobs/ 如图:

 
 

可以看到,有一个Job任务已经运行完毕了。

案例二:做一个每日的PV分析

Step1、首先,我们将网站的访问数据导入到hive当中,执行:

$ cat hql-file/track-log.hql

其中track-log.hql文件如下:

 
该部分内容可以参看Hive框架基础(一)

Step2、通过Hive查看track_log文件在哪

hive> desc formatted track_log;

如图:注意红框内容,对于我们来讲,有用的即:/user/hive/warehouse/track_log/2015082818

 
 
 
 

Step3、将日志数据读入到RDD中等待分析

scala> val rdd = sc.textFile("/user/hive/warehouse/track_log/2015082818")

Step4、清洗无效的数据,即空白行,以及url字段为空的,我们要过滤掉

1、先过滤空白行

2、再分割字段值

3、最后过滤url字段为空的

综合来写:

scala> val validRdd = rdd.filter(line => line.length > 0).map(_.split("\t")).filter(arr => arr(1).length > 0)

当然了,此时你可以count一下,看看过滤后剩下多少数据

scala> validRdd.count

 
 

Step4、将URL做map映射,比如做出这样的映射:(今日日期, 1)

那么今日的日期在tracktime字段,属于分割后的数组的第17个索引处

在hive中我们查看一下该日期的格式:

hive> select tracktime from track_log limit 1;

如图:

 
 

那么截取出2015-08-28应该很容易,所以:

scala> val mapRdd = validRdd.map(arr => (arr(17).substring(0, 10), 1))

Step5、你懂得,再来一个Reduce即可

scala> val reduceRdd = mapRdd.reduceByKey(_ + _)

完事之后可以查看一下结果:

scala> reduceRdd.collect

如图:

 
 

当然了也可以一气呵成走你:

scala> sc.textFile("/user/hive/warehouse/track_log/2015082818")

.filter(line => line.length > 0)

.map(_.split("\t"))

.filter(arr => arr(1).length > 0)

.map(arr => (arr(17).substring(0, 10), 1))

.reduceByKey(_ + _)

.collect

Step6、我们使用Hive来验证一下

注意如果你的Yarn没有启动,需要将Hive设置成Local模式:

hive> set hive.exec.mode.local.auto = true;

然后执行:

 
 

结果如图:

 
 

对比可知,两个结果是一样的。

案例三:PV和UV分析

PV:即页面访问次数

UV:即不同用户访问页面次数

Step1、读取网站日志文件生成RDD对象

scala> val rdd = sc.textFile("/user/hive/warehouse/track_log")

Step2、过滤不必要的数据,并生成map映射,注意此时的操作与之前的案例略有不同,请注意观察,如图:

scala> val mapRdd = rdd.filter(_.length > 0).map(line => {

| val arr = line.split("\t")

| val date = arr(17).substring(0, 10)

| val guid = arr(5)

| val url = arr(1)

| (date, guid, url)

| }).filter(tuple => tuple._3.length > 0)

 
 

Step3、可选步骤,此处可以将数据cache到内存中,注意,cache后,不会立刻缓存到内存中,需要执行一个action,比如count,take,collect都可以

scala> mapRdd.cache

scala> mapRdd.count

在此之后就可以在4040端口的页面是storge选项中看到缓存到内存中的数据信息,如图:

 
 

Step4、统计PV

scala> val pvRdd = mapRdd.map(tuple => (tuple._1, 1)).reduceByKey(_ + _)

scala>  pvRdd.first,如图:

 
 

Step5、UV统计

scala> val uvRdd = mapRdd.map(tuple => (tuple._1 + "_" + tuple._2, 1)).distinct.map(tuple => {

val arr = tuple._1.split("_")

(arr(0), 1)

}).reduceByKey(_ + _)

 
此时可以自行使用uvRdd.first查看结果,不再展示

Step6、合并PV和UV的结果进行显示

union方式:

scala> val pv_uvRdd = pvRdd.union(uvRdd)

scala> pv_uvRdd.collect,如图:

 
 

join方式:

scala> val pv_uvRdd = pvRdd.join(uvRdd)

scala> pv_uvRdd.first,如图:

 
 

验证:使用Hive或者SparkSQL验证结果一致性

首先创建SQL语句:

 
 

SparkSQL方式:

scala> val sql = """ 上边的SQL代码 """,如图:

 
 

然后执行:

scala> val result = sqlContext.sql(sql)

 
 

scala> result.show()

 
 

尖叫提示:如果你的hive使用了thrift的metastore方式,请把hive的hive-site.xml文件软连接到spark的conf目录下!!否则上述指令将会出现找不到table的错误。

HIVE方式:直接使用Hive客户端执行上面的SQL语句,如图:

 
 

Spark任务历史服务

对于Yarn有mr-historyserver

对于Spark有SparkHistory

所以应该很容易明白这是一个任务日志的历史服务,比如你可以查看昨天半夜运行的任务情况。

开启这个服务也很简单:

可以参看:http://spark.apache.org/docs/1.6.1/monitoring.html

Step1、配置参数

配置:spark-env.sh,日志默认是保存在本地的,此刻我们将日志保存到HDFS系统当中如图:

 
 

配置:spark-defaults.conf,spark启动时默认加载的配置文件

 
 

Step2、在HDFS系统中创建目录/user/z/spark-events

Step3、将配置文件重新scp到其他节点之后,重启服务,然后开启历史服务

$ sbin/start-history-server.sh

JPS看一眼:

 
 

然后在浏览器打开:http://z01:18080/

如图:

 
 

Step4、测试玩一玩?

$ bin/spark-shell --master spark://z01:7077

随便执行执行一个我们之前的案例任务,即可,运行几个任务,成功运行几个,再失败几个,如图:

 
 

注意红框内容,如果你当前的spark-shell没有退出,那么该任务就是属于正在运行的任务。请自行切换观察即可。

* 总结

对于RDD到RDD的 操作,我们称之为Transformation操作

例如:我们在案例中使用的过滤,或者map,或者reduce等等

对RDD到其他类型的操作,我们称之为Action

例如:我们在案例中使用的top,或者take、collect等操作

另外RDD中的数据可以持久化到内存中来操作,使用:

rdd.cache来操作,比较适用于频繁使用的。

这一节我们大概了解了Spark的操作,也应该更加深刻的熟悉了Scala的操作。下一节我们针对Spark进行更深入的探讨。


个人微博:http://weibo.com/seal13

QQ大数据技术交流群(广告勿入):476966007


作者:Z尽际
链接:https://www.jianshu.com/p/136874812e11
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

SparkCore基础(一)的更多相关文章

  1. SparkCore基础(二)

    * SparkCore基础(二) 继续探讨SparkCore,开门见山,不多废话. SparkApplication结构探讨 包含关系: 之前我们运行过很多App了,其实每一个App都包含若干个Job ...

  2. SparkStreaming基础

    * SparkStreaming基础 打开之前构建好的Maven工程,如何构建?请参看SparkCore基础(二)的最后部分. 在SparkCore中,我们操作的数据都在RDD中,是Spark的一个抽 ...

  3. spark-初阶①(介绍+RDD)

    spark-初阶①(介绍+RDD) Spark是什么? Apache Spark 是一个快速的, 多用途的集群计算系统, 相对于 Hadoop MapReduce 将中间结果保存在磁盘中, Spark ...

  4. spark基础知识(1)

    一.大数据架构 并发计算: 并行计算: 很少会说并发计算,一般都是说并行计算,但是并行计算用的是并发技术.并发更偏向于底层.并发通常指的是单机上的并发运行,通过多线程来实现.而并行计算的范围更广,他是 ...

  5. [转] Spark快速入门指南 – Spark安装与基础使用

    [From] https://blog.csdn.net/w405722907/article/details/77943331 Spark快速入门指南 – Spark安装与基础使用 2017年09月 ...

  6. 《OD学spark》20160924scala基础

    拓展: Hadoop 3.0 NameNode HA NameNode是Active NameNode是Standby可以有多个 HBase Cluster 单节点故障? HBaster -> ...

  7. Storm框架基础(一)

    * Storm框架基础(一) Storm简述 如果你了解过SparkStreaming,那么Storm就可以类比着入门,在此我们可以先做一个简单的比较:  在SparkStreaming中: 我们曾尝 ...

  8. SparkSQL基础

    * SparkSQL基础 起源: 1.在三四年前,Hive可以说是SQL on Hadoop的唯一选择,负责将SQL编译成可扩展的MapReduce作业.鉴于Hive的性能以及与Spark的兼容,Sh ...

  9. java基础集合经典训练题

    第一题:要求产生10个随机的字符串,每一个字符串互相不重复,每一个字符串中组成的字符(a-zA-Z0-9)也不相同,每个字符串长度为10; 分析:*1.看到这个题目,或许你脑海中会想到很多方法,比如判 ...

随机推荐

  1. 判断QString是否为纯数字,查找自身最长重复子字符串

    1.判断QString是否为纯数字 bool IsDigitString(QString strSource) { bool bDigit = false; if (strSource.isEmpty ...

  2. iOS开发之UIAlertController的适配

    在iOS8中,只能用UIAlertController.而原来的UIAlertView及UIActionSheet已经被抛弃掉了.但是如果一台iOS 7 的手机运行到有UIAlertControlle ...

  3. php和js区别

    php和js区别 两者在语法上类似,楼上说的对,js=javascript是工作在浏览器端的脚本语言,他所提交的数据是交给浏览器来处理的.但是现在的Ajax技术已经可以把js提交的数据交付到浏览器来处 ...

  4. ES 遇到 unassigned shard如何处理?

    解决方法:(1)如果是红色的,可以直接分片shard给你认为有最新(或最多)数据的节点.见下: 摘自:https://discuss.elastic.co/t/how-to-resolve-the-u ...

  5. ORACLE 索引批量重建

    按用户批量重建索引: 按用户将此用户下面非临时表上面的索引全部重建,此过程建议在SYS用户下面执行: CREATE OR REPLACE PROCEDURE BATCH_REBUILD_INDEX(U ...

  6. 关于Java集合的小抄--转

    原文地址:http://calvin1978.blogcn.com/articles/collection.html 在尽可能短的篇幅里,将所有集合与并发集合的特征.实现方式.性能捋一遍.适合所有&q ...

  7. Android官方培训课程中文版(v0.9.7)

    Android官方培训课程中文版(v0.9.7) Google Android团队在2012年的时候开设了Android Training板块 - http://developer.android.c ...

  8. 如何在Windows下安装Linux子系统(Ubuntu,openSUSU,SUSU Linux Server)

    注意:只有win10才能安装,安装的linux没有图形界面. 1.首先在win10设置 --> 更新与安装 --> 针对开发人员 ,选择开发人员模式. 2.win10 Cortana -- ...

  9. rman备份工具简介

    RMAN工具简介: 备份的文件: 数据文件 归档日志 控制文件(当前控制文件) spfile 自动管理备份相关元数据 文件名称 完成备份的scn 以数据块为单位,只备份使用过的数据块(物理层面判断是否 ...

  10. H5中 input消除默认,取消在手机上的点击高亮效果

    input消除默认,代码如下    input{             -webkit-tap-highlight-color: rgba(255, 255, 255, 0);            ...