Spark入门梳理2-Spark基础知识

Spark编程基础-搭配Jupyter

上节我们说道了Spark的基础知识和原理,这一节我们具体说一下Spark的编程基础

1.1 RDD编程

1.1.1 RDD创建

RDD的两种创建方式:

  1. 读取一个外部数据。比如:
    * 本地加载文本文件;
    * 从HDFS文件系统加载数据集
    * SequenceFile文件(Hadoop提供的,由二进制序列化过的键值的字节流组成的文本存储文件)
    * 其他符合Hadoop InputFormat格式的文件
  2. 调用SparkContext的parallelize方法,在Driver中已经存在的集合上创建

1.1.2 文件系统中加在数据集

在jupyter中,可以使用以下代码读取本地文件:

from pyspark import SparkContext
import os
os.environ['JAVA_HOME']	 # 此处查看自己的java_home 路径是否配置正确
sc = SparkContext( 'local', 'test')
textFile = sc.textFile("./word.txt") # 也可以使用绝对路径
# sc.textFile("file:///你的路径/word.txt")
textFile.first()
textFile.saveAsTextFile('./writeback') # 保存你的文件 练习
logData = sc.textFile(logFile, 2).cache()
numAs = logData.filter(lambda line: 'a' in line).count()
numBs = logData.filter(lambda line: 'b' in line).count()
print('Lines with a: %s, Lines with b: %s' % (numAs, numBs))
  • 接下来我们看下 sc.textFile详细讲解
  • 在你代码里面输入 help(sc.textFile)
    Help on method textFile in module pyspark.context:
    
    textFile(name, minPartitions=None, use_unicode=True) method of pyspark.context.SparkContext instance
        Read a text file from HDFS, a local file system (available on all
        nodes), or any Hadoop-supported file system URI, and return it as an
        RDD of Strings.
        
        If use_unicode is False, the strings will be kept as `str` (encoding
        as `utf-8`), which is faster and smaller than unicode. (Added in
        Spark 1.2)
        
        >>> path = os.path.join(tempdir, "sample-text.txt")
        >>> with open(path, "w") as testFile:
        ...    _ = testFile.write("Hello world!")
        >>> textFile = sc.textFile(path)
        >>> textFile.collect()
        ['Hello world!']
    
  • 上面这段代码是对 sc.textFile 的解释,这里我们看到use_unicode 这个参数假设是False的时候 可以让我更快更小的运行,而且是UTF-8的格式,而unicode和string的区别这个熟悉python的应该都很清楚了,我们可以根据自己需求进行定制

在使用spark读取文件时,需要说明几个点:
(1)如果使用了本地文件系统的路径,那么,必须要保证在所有的worker节点上,也都能够采用相同的路径访问到该文件,比如,可以把该文件拷贝到每个worker节点上,或者也可以使用网络挂载共享文件系统。
(2)textFile()方法的输入参数,可以是文件名,也可以是目录,也可以是压缩文件等。比如,textFile(“/my/directory”), textFile(“/my/directory/.txt”), and textFile(“/my/directory/.gz”).
(3)textFile()方法也可以接受第2个输入参数(可选),用来指定分区的数目。默认情况下,Spark会为HDFS的每个block创建一个分区(HDFS中每个block默认是128MB)。你也可以提供一个比block数量更大的值作为分区数目,但是,你不能提供一个小于block数量的值作为分区数目。

1.1.3 通过并行集合创建RDD

直接上例子:

ary = [1, 2, 3, 4, 5]
s_ary = sc.parallelize(ary)
s_ary.variance

输出如下:
<bound method RDD.variance of ParallelCollectionRDD[6] at parallelize at PythonRDD.scala:195>
从执行结果来看,生成了一个collect的RDD

1.1.4 RDD操作

RDD被创建好以后,在后续使用过程中一般会发生两种操作:

  1. 转换(Transformation): 基于现有的数据集创建一个新的数据集。
  2. 行动(Action):在数据集上进行运算,返回计算值。
1.1.4.1 转换操作
  • 下面列出一些常见的转换操作(Transformation API):
    • filter(func):筛选出满足函数func的元素,并返回一个新的数据集
    • map(func):将每个元素传递到函数func中,并将结果返回为一个新的数据集
    • flatMap(func):与map()相似,但每个输入元素都可以映射到0或多个输出结果
    • groupByKey():应用于(K,V)键值对的数据集时,返回一个新的(K, Iterable)形式的数据集
    • reduceByKey(func):应用于(K,V)键值对的数据集时,返回一个新的(K, V)形式的数据集,其中的每个值是将每个key传递到函数func中进行聚合
1.1.4.2 行动操作

行动操作是真正触发计算的地方。Spark程序执行到行动操作时,才会执行真正的计算,从文件中加载数据,完成一次又一次转换操作,最终,完成行动操作得到结果。
下面列出一些常见的行动操作(Action API):

  • count() 返回数据集中的元素个数
  • collect() 以数组的形式返回数据集中的所有元素
  • first() 返回数据集中的第一个元素
  • take(n) 以数组的形式返回数据集中的前n个元素
  • reduce(func) 通过函数func(输入两个参数并返回一个值)聚合数据集中的元素
  • foreach(func) 将数据集中的每个元素传递到函数func中运行*

1.2 键值对RDD

  1. 从文件中加载
    在jupyter对应路径新建一个txt文件,此处使用map()函数实现
lines = sc.textFile("file:///usr/local/spark/mycode/pairrdd/word.txt")
output: org.apache.spark.rdd.RDD[String] = file:///usr/local/spark/mycode/pairrdd/word.txt MapPartitionsRDD[1] at textFile at <console>:27
pairRDD = lines.flatMap(line => line.split(" ")).map(word => (word,1))
pairRDD: org.apache.spark.rdd.RDD[(String, Int)] = MapPartitionsRDD[3] at map at <console>:29
pairRDD.foreach(println)
(i,1)
(love,1)
(hadoop,1)
(i,1)
(love,1)
(Spark,1)
(Spark,1)
(is,1)
(fast,1)
(than,1)
(hadoop,1)

我们之前在“第一个Spark应用程序:WordCount”章节已经详细解释过类似代码,所以,上面代码不再做细节分析。从代码执行返回信息:pairRDD: org.apache.spark.rdd.RDD[(String, Int)] = MapPartitionsRDD[3] at map at :29,可以看出,返回的结果是键值对类型的RDD,即RDD[(String, Int)]。从pairRDD.foreach(println)执行的打印输出结果也可以看到,都是由(单词,1)这种形式的键值对。

  1. 通过并行集合创建RDD
scala> val list = List("Hadoop","Spark","Hive","Spark")
list: List[String] = List(Hadoop, Spark, Hive, Spark)
 
scala> val rdd = sc.parallelize(list)
rdd: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[11] at parallelize at <console>:29
 
scala> val pairRDD = rdd.map(word => (word,1))
pairRDD: org.apache.spark.rdd.RDD[(String, Int)] = MapPartitionsRDD[12] at map at <console>:31
 
scala> pairRDD.foreach(println)
(Hadoop,1)
(Spark,1)
(Hive,1)
(Spark,1)

1.3 共享变量(分布式)

在默认情况下,当Spark在集群的多个不同节点的多个任务上并行运行一个函数时,它会把函数中涉及到的每个变量,在每个任务上都生成一个副本。但是,有时候,需要在多个任务之间共享变量,或者在任务(Task)和任务控制节点(Driver Program)之间共享变量。为了满足这种需求,Spark提供了两种类型的变量:广播变量(broadcast variables)和累加器(accumulators)。广播变量用来把变量在所有节点的内存之间进行共享。累加器则支持在所有不同节点之间进行累加计算(比如计数或者求和)。

  1. 广播变量
  • 广播变量(broadcast variables)允许程序开发人员在每个机器上缓存一个只读的变量,而不是为机器上的每个任务都生成一个副本。通过这种方式,就可以非常高效地给每个节点(机器)提供一个大的输入数据集的副本。Spark的“动作”操作会跨越多个阶段(stage),对于每个阶段内的所有任务所需要的公共数据,Spark都会自动进行广播。通过广播方式进行传播的变量,会经过序列化,然后在被任务使用时再进行反序列化。这就意味着,显式地创建广播变量只有在下面的情形中是有用的:当跨越多个阶段的那些任务需要相同的数据,或者当以反序列化方式对数据进行缓存是非常重要的。
  1. 累加器
  • 累加器是仅仅被相关操作累加的变量,通常可以被用来实现计数器(counter)和求和(sum)。Spark原生地支持数值型(numeric)的累加器,程序开发人员可以编写对新类型的支持。如果创建累加器时指定了名字,则可以在Spark UI界面看到,这有利于理解每个执行阶段的进程。
    一个数值型的累加器,可以通过调用SparkContext.longAccumulator()或者SparkContext.doubleAccumulator()来创建。运行在集群中的任务,就可以使用add方法来把数值累加到累加器上,但是,这些任务只能做累加操作,不能读取累加器的值,只有任务控制节点(Driver Program)可以使用value方法来读取累加器的值。

1.4 数据读写

1.4.1 文件数据读写

这里只讲解本地文件读写,不同格式文件读写基本一致,只是表现形式上有所不同,有需要的同学参考:文件读写参考

  • 在我们已经搭建好的jupyter和spark环境下,新建一个 ****.ipynb文件,新建一个word.txt,随便输入一些内容
  • 先上代码
    from pyspark import SparkContext
    import os
    sc = SparkContext( 'local', 'test')
    # help(SparkContext)
    textFile = sc.textFile("./word.txt")
    textFile.first()
    textFile.saveAsTextFile('./writeback')  # 保存新文件到writeback路径
    # logData = sc.textFile(logFile, 2).cache()
    # numAs = logData.filter(lambda line: 'a' in line).count()
    # numBs = logData.filter(lambda line: 'b' in line).count()
    # print('Lines with a: %s, Lines with b: %s' % (numAs, numBs))
    
  • 之后在目录中 输入
    cd /writeback
    ls
    
  • 执行结果如下:
    part-00000
    _SUCCESS
    
  • cat part-00000查看文件内容可以看出和word.txt中的数据是一模一样
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值