SPARK的学习

Spark着重学习这几点:

  • scala 语言
  • Spark编程
    RDD 的理解使用
    DStream 的理解与使用
scala 语言

scala 学习我看的是《scala 编程》,作者是scala语言的开发者Martin Odersky 编写的,作为入门书非常不错。也可以去看英文原版 Programming in Scala ,目前已经出到了第三版。另外熟悉 java 语言的也可以到官方文档去学习:A SCALA TUTORIAL FOR JAVA PROGRAMMERS - Java程序员的 scala 使用教程 。

我自己只是很简单地看完了《scala 编程》的前七章,了解大概的语法之后就开始敲东西尝试去了。但后来翻了下目录发现,从第九章开始是要真正好好看的部分,能深入 scala 语言,所以还是需要继续进行学习的。

scala 语言很简短,相比起 java 的代码量来说缩短了估计三分之一。夸张一点说,如果使用得当,可以缩短到十分之一的代码量。scala 我印象最深刻的就是函数式。举个例子,java 里面定义类是这样的——

class MyClass{
    private String str;
    private int data;
    public MyClass(String str, int data){
        this.str = str;
        this.data = data;
    }
}

然而,scala 里边只需要这样——

class MyClass(str:String,data:int)

由此可见用scala编程真的很省力,但具体实现的时候还是根据实际项目来选择 scala 语言吧。

Spark编程

这里简单提一下 MapReduce 和 Spark 之间的区别(两者都是基于YARN上运行的)。

MapReduce 是 Hadoop 的处理数据的模型,有三个阶段,Map — Shuffle — Reduce。Map 在每个处理机器上进行各自的task计算,每次的计算都要进行一次I/O操作,将结果写入磁盘,非常耗时,不适合迭代函数。

而Spark则是在内存中执行,省略了写入磁盘的操作,适合迭代函数。因此计算速度上来说,Spark将计算的处理速度提高了一百倍。

  • RDD

RDD英文全称是Resilient Distributed Datasets,即弹性分布式数据集。官方权威的说明在这里:RDD Programming Guide 。

在高层级中,每个Spark应用程序都由一个驱动程序组成,该程序运行用户的主函数,并在集群上执行各种并行操作。Spark提出的主要抽象概念就是弹性分布式数据集(RDD),它是跨集群节点的一个元素集合,可以并行地执行各种操作。 RDDs 是由 Hadoop 文件系统中的一个文件(或任何其他 Hadoop 支持的文件系统),或者驱动程序中现有的 Scala 集合,转换创建而成。用户还可以让Spark 将一个 RDD 保存在内存中,以便在之后的并行操作中高效地重用。另外,RDDs 还能自动从节点故障中恢复。

Spark 中的第二个抽象概念就是共享变量,可以在并行操作中使用。默认情况下,当 Spark 作为一组任务在不同的节点上并行运行一个函数时,函数中使用的每个变量的副本将会被发送到每个任务中。有时,一个变量需要通过任务分享,或者在任务和驱动程序之间分享。Spark支持两种分享变量,分别是广播变量和累加器(执行统计或者总和计算)。

其实简单说来,我的理解是把RDD当成一个简单的容器,把数据往里一塞,最后流出来的是自己想要的结果。

  • Spark程序的工作流程

从外部创建输入RDD
——> filter() 对 RDD 进行转化操作,定义新的 RDD
——> 告诉 Spark 对需要被重用的中间结果 RDD 执行 persist() 操作
——> 使用 first() 等操作开始一次并行计算,Spark对计算进行优化之后再执行

  • 创建 RDD

RDD创建之前要链接到Spark。

val conf = new SparkConf().setAppName(appName).setMaster(master)
new SparkContext(conf)

RDD创建有两种方式,最常见的是文件方式创建RDD。

a. 读取外部数据集(文件、hive 数据库等)

val files = sc.textFile(input)  //input为文件路径

b. 驱动程序中的集合(list 、set 等)

  • RDD操作

具体看官方给的 API 文档 RDD API - org.apache.spark.rdd,写的非常详细,根据实际需要去官网查询使用。

RDD的操作有两类,下面以集合 {1,2,3,3} 为例写常用的一些操作。

a. 转化操作

操作 说明 举例 结果
map() 处理RDD中的每个元素,返回新的RDD rdd.map(x => x+1) {2,3,4,4}
flatmap() 处理RDD中每个元素,将每个元素创建为新的RDD,切割单词时使用
filter() 按条件过滤RDD中每个元素 rdd.filter(x > 1) {2,3,3}
distinct() RDD中元素去重 rdd.distinct() {1,2,3}

b. 基本执行操作

操作 说明 举例 结果
collect() 返回RDD中所有的元素 rdd.collect() {1,2,3,3}
count() 返回RDD集合中元素个数 rdd.count() 4
reduceByKey() 返回RDD集合中各个元素出现的次数 rdd.reduceByKey(_+_) {(1,1),(2,1),(3,2)}
foreach() 对每个元素使用指定函数function(),无返回值 rdd.foreach(print()) 控制台输出每个元素

实战

编写spark程序,实现这样一个功能,读取一个文本文档,统计其中的单词出现频率并输出。文本文档中的内容如下。

Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal. Now we are engaged in a great civil war, testing whether that nation, or any nation so conceived and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this.

思路:使用文档创建RDD,以空格分割每个单词,删除单词尾部的标点符号,使用reduceByKey()进行统计输出。

用 maven 构建项目,添加下述依赖:

org.apache.spark
spark-core_2.11
2.3.1

具体实现的代码:

import org.apache.spark.{SparkContext,SparkConf}

object WordCount {
  def main(args: Array[String]):Unit = {
    if (args.length < 2){
      System.err.println("needs two param  ")
      System.exit(1)
    }
    val input = args(0)
    val output = args(1)      
    val conf = new SparkConf().setAppName("App").setMaster("local")
    val sc = new SparkContext(conf)
    val files = sc.textFile(input)
    val words = files.flatMap(_.split(" ")).map( x => isLetter( x ))
      .map((_,1)).reduceByKey(_ + _)
    words.collect().foreach(println)      //控制台打印输出
    words.saveAsTextFile(output)
    sc.stop()
  }
  //处理字符串末尾的符号
  def isLetter(str:String) = if (!str(str.length-1).isLetter) str.slice(0,str.length-1) else str
  //slice函数返回的值为(start, finish)的字符串,但不包括finish位置的字符
}

将上述项目打包成 jar 包(我打包的 jar 包叫 scala01.jar),启动 hadoop 的 hdfs,在原生的Spark文件目录下(Spark 去官网下载对应的包,记得配置 /etc/profile 文件,然后 source /etc/profile 使环境生效)命令本地执行:

# spark-submit --class    
$ bin/spark-submit --class WordCount ~/Downloads/scala01.jar hdfs://localhost:9000//input/word.txt hdfs://localhost:9000//output01

打开浏览器 localhost:50070 查看是否有输出,如图所示。详细的结果可以在 terminal 的控制台看到,也可以使用dfs -cat 查看。

输出的结果

最后的最后。

有一个地方我不是很明白,我想要让 spark 在本地启动的 yarn 上面跑一下,配置了 {$SPARK_HOME}/conf 中的 spark-env.sh 文件,打开 localhost:8080 查看 YARN 是否执行任务,结果成功输出,但是 accepted 任务还是为空,我理解的是 Spark 并没有部署到本地的YARN上。我配置的文件如下:

# Options read in YARN client/cluster mode
# - SPARK_CONF_DIR, Alternate conf dir. (Default: ${SPARK_HOME}/conf)
# - HADOOP_CONF_DIR, to point Spark towards Hadoop configuration files
# - YARN_CONF_DIR, to point Spark towards YARN configuration files when you use YARN
# - SPARK_EXECUTOR_CORES, Number of cores for the executors (Default: 1).
# - SPARK_EXECUTOR_MEMORY, Memory per Executor (e.g. 1000M, 2G) (Default: 1G)
# - SPARK_DRIVER_MEMORY, Memory for Driver (e.g. 1000M, 2G) (Default: 1G)
export SPARK_CONF_DIR=/home/hadoop/soft/spark-2.3.1-bin-hadoop2.7/conf
export HADOOP_CONF_DIR=/home/hadoop/soft/hadoop/etc/hadoop
export YARN_CONF_DIR=/home/hadoop/soft/hadoop/etc/hadoop

若是有哪位大神知道答案的话,能否评论中告知一下,在此谢谢了。

你可能感兴趣的:(SPARK的学习)