spark学习笔记五:spark编程

来源:互联网 发布:知乎乒乓球衰败 编辑:程序博客网 时间:2024/05/22 13:13

Spark编程

Window下的IDE环境

安装ide前先安装scala。我在配置eclipse的过程中遇到一些莫名其妙的问题。建议直接使用IntelliJ IDEA。使用方法如下。

1.      使用IntelliJ IDEA新建普通项目或maven项目。

2.      以普通项目为例,新建项目后,需要依赖spark的jar包,在安装包中可以找到,名为spark-assembly-*.jar。File->Project Structure->Library可以选择这个jar包从而添加到依赖路径中。如果需要依赖其他jar包,也通过这种方式加入。比如,以下的例子需要使用hbase依赖,所以这里还需要依赖hbase-0.94.17.jar。

3.      编码完成后,使用File->Project Structure->Artifacts可以为工程添加一个编译目标,选择“+”->JAR->From Modules …. ,跳出对话框,这里需要选择main函数,以及依赖的编译方式:1.是集成到一个jar包中,2.或者是把所有jar包放到一个目录下。这里,我选择copy to the output…..,即依赖jar包和编译产生的jar包会放到一个输出目录下。

4.      编译的方式是:Build->Build Artifacts。这步操作完成后,会在输出目录产生各个jar包,这些jar包在以后将被提交给spark运行。

 

Spark属性的配置

Spark可配置的属性一般包括:针对某个应用的应用名、master模式(yarn、local、standalone)、master地址、worker可用的内存(这个一般用在worker实例上)。对于某个spark应用而言,Spark属性可以通过以下几种方式来进行配置:

1.      编程时使用SparkConf类,调用其set函数来设置属性。这将以后文介绍。

2.      编程时使用SparkContex类,这个类的也可以用来设置属性,比如,在他的构造函数可选地传入应用名、master地址等。

3.      使用spark-submit脚本提交应用时,由命令选项传入。

4.      使用环境变量,环境变量一般在$SPARK_HOME/conf/spark-env.sh中配置。spark-env.sh.template文件是其模板,这个文件中的注释基本给出了所有可以配置的选项。

5.      使用配置文件,配置文件是$SPARK_HOME/conf/spark-default.conf。spark-defaults.conf.template是其模板文件,这个文件中的注释给出了几个可以配置的选项。

6.      使用$SPARK_HOME/conf/log4j.properties文件,log4j.properties.template是其模板文件。

一般推荐使用3、4、5三种方式来配置,这样灵活性高。

 

API的使用

Spark编程,其实就是scala语言 + spark的api。一段典型的代码如下所示:

object Stat {
  def main( args:Array[String] ): Unit ={
    val table = args(0)
    val family = args(1)
    val column = args(2)
    val startTime = args(3)
    val endTime = args(4)
    val saveFile = args(5)
    val spConf= new SparkConf()
    /*spConf.setMaster(args(0))
     .setAppName(args(1)).setSparkHome(System.getenv("SPARK_HOME"))
     .setJars(Seq(System.getenv("SPARK_JAR_PATH")))*/
    val spContext= newSparkContext(spConf)

    val hbConf =HBaseConfiguration.create()

    hbConf.set(TableInputFormat.INPUT_TABLE,table)
   hbConf.set(TableInputFormat.SCAN_COLUMN_FAMILY, family )
   hbConf.set(TableInputFormat.SCAN_TIMERANGE_START, startTime )
   hbConf.set(TableInputFormat.SCAN_TIMERANGE_END, endTime )

    val hbRdd =spContext.newAPIHadoopRDD(hbConf,
      classOf[TableInputFormat],
     classOf[org.apache.hadoop.hbase.io.ImmutableBytesWritable],
     classOf[org.apache.hadoop.hbase.client.Result] )

    val strRDD = hbRdd.map[String]( (tup:(org.apache.hadoop.hbase.io.ImmutableBytesWritable,org.apache.hadoop.hbase.client.Result)) => new String( tup._2.getValue(family.getBytes,column.getBytes)) )
    strRDD.saveAsTextFile(saveFile)

  }
}

这段代码从hbase表中读取出某个时间段内的数据,并保存到hdfs上。对照以上代码,下文将给出代码的解释。

 

1.      SparkConf

SparkConf用于配置本应用的基本选项,包括master地址、应用名、jar包地址等。具体的可配置选项参考api文档。基本的使用方法如下:

val conf = newSparkConf().setAppName(appName).setMaster(master)

master可以是”local”,代表在本机运行,这一般是调试时候用。也可以是“spark:// ”、“yarn://”、“Mesos://”三种取值。另外,像master和AppName,一般建议由程序的选项传入,而不要使用SparkConf或SparkContext来设置,如以上示例所示,这样灵活性好。

2.      sparkcontex

SparkContext是spark应用的上下文,在一个JVM中只能有一个实例有效,所以一般只new一个。它的创建方法如下:

val spContext= new SparkContext(spConf)

3.      RDD

示例中的spContext.newAPIHadoopRDD语句用于产生一个RDD。本质而言,一个spark应用实际上是对各个RDD对象的操作,这些操作包括:变换、持久化、产出(就是action的概念)。

RDD的来源有两种:

1)      把scala中的集合并行化(分片);

把集合并行化的方法是:

val data = Array(1, 2, 3, 4, 5)

val distData =sc.parallelize(data)

val distData = sc.parallelize(data,10)

一般是按照每个cpu有2-4个分片的方式进行分片,上面的最后一种方式是手动设置分片数。

 

2)      从外部存储介质中读入。

从外部存储介质读入的方法:

scala> val distFile =sc.textFile("data.txt")

distFile: RDD[String] = MappedRDD@1d4cee08

textFile()中的文件名允许使用目录、文件名通配符。一般而言,从HDFS读入的话,是一个文件block对应一个rdd分片。textFile读文件的方式是一行作为一条记录。另外还有SequenceFiles是把[k,v]格式的数据读入。

        

示例中的newAPIHadoopRDD用于读取Hadoop数据源,通过代码中各项配置,这个RDD实际上是从hbase中读取数据,其逻辑请参考以上代码。

 

调用persist或cache函数可以把RDD数据持久化到本地,可以持久化到内存、磁盘,也可以在其他work上放置副本。

 

4.      动作

strRDD.saveAsTextFile(saveFile)是一个动作,用于把RDD产出到文件中,这个saveFile可以给出一个hdfs的地址。

 

Worker间数据共享机制

正常上,drive把函数分发到每个work上运行,这个函数是个闭包,包含变量值。但是spark还是提供了两种cluster间共享数据的机制。

Broadcast Variables

广播变量,即由drive一次性把变量广播给各个work(只广播一次),这个数据在各个work上是只读的,之后各个work一旦用到这个变量,就不需要作为闭包再传一次。当然,必须保证这个变量是只读的。

使用方法如下:

scala> val broadcastVar =sc.broadcast(Array(1, 2, 3))

broadcastVar: org.apache.spark.broadcast.Broadcast[Array[Int]]= Broadcast(0)

scala> broadcastVar.value

res0: Array[Int] = Array(1, 2, 3)

定义了val broadcastVar = sc.broadcast后,之后要使用这个值就直接broadcastVar.value即可。

 

Accumulators

累加器,即各个work可以对这个累加器执行加法操作,但不可读。只有drive可读,并且可以在ui上显示出来。用法如下:

scala> val accum = sc.accumulator(0,"My Accumulator")

accum: spark.Accumulator[Int] = 0

 

scala> sc.parallelize(Array(1, 2, 3,4)).foreach(x => accum += x)

 

应用提交

在Standalone模式下,提交的方式是:

spark-submit –master<mater地址> --name <应用名> --class <main函数所在类> --jars <所依赖的jar包,spark-assembly可以不用包含进来> --executor-memory <应用在每个executor占用的内存>--total-executor-cores <应用占用的总CPU核数> <要运行的jar包> <参数>

如果master地址在配置文件中指定了,这里就不需要--mastert选项。它可选择的参数有        spark://host:port            standalone模式

mesos://host:port            mesos模式

yarn                                      yarn模式

local[n]                                 在本地用n个核运行spark应用。

0 0
原创粉丝点击