spark基本使用

spark使用

spark基本配置

python命令行

启动pyspark
cd /usr/local/spark
./bin/pyspark
统计文本的行数
lines = sc.textFile("file:///usr/local/spark/README.md")
lines.count()

* 在这里需要使用本地文件系统的绝对路径,因为在pyspark中,默认的根目录是localhost:9000,在这个目录下没有README.md文件,如果使用相对路径,可能会出现py4j.protocol.Py4JJavaError: An error occurred while calling z:org.apache.spark.api.python.PythonRDD.collectAndServe.的问题
* 参考链接:https://www.cnblogs.com/yangzhang-home/p/6056133.html

配置spark,使其使用jupyter notebook

  • 在.bashrc中添加
    export PYSPARK_DRIVER_PYTHON=jupyter
    export PYSPARK_DRIVER_PYTHON_OPTS=”notebook”

  • source之后,启动pyspark即可,如果要修改启动时的文件夹,可以参考:https://www.zhihu.com/question/31600197,修改配置文件中的notebooik_dir即可。

RDD基础

  • RDD(Resilient Distributed Dataset)是spark对数据的核心抽象,它是分布式的元素集合,在spark程序中,所有的操作都可以归类为3中:创建RDD、RDD的转化(transformation)以及RDD的行动操作(action)。
  • spark在执行action的时候,才会真正地去计算

spark的程序流程

RDD的persisit方法会将该RDD对象持久化到内存中,对于可能会被重复调用的RDD对象,这种方法可以减少计算量,因此主要的流程为:
* 从外部数据创建出输入RDD
* 进行一些RDD对象的转化,同时创建一些新的RDD对象
* 对需要被重复计算的中间结果进行persist操作
* 使用行动操作(action)来触发一次计算

创建RDD

  • 可以从外部数据集创建RDD,也可以直接在程序里对一个集合进行并行化

    lines = sc.parallelize( ["first", "second"] )
    print( lines.count() )
    print( lines.first() )
    

RDD转化

  • 之前使用的filter就是最常用的RDD转化操作,可以找出集合中满足条件的内容
  • 转化操作可以操作任意数量的RDD

RDD执行

  • 刚才在RDD转化时,其实并未真正计算,当RDD执行时,才会去计算
  • count、first等都是常用的行动操作

RDD的谱系图

  • RDD的谱系图是用来记录不同RDD之间的依赖关系,可以使用谱系图来实现按需要计算RDD,而非计算所有RDD,同时,当持久化的RDD的信息出现部分丢失的情况时,也会根据这种依赖关系来恢复丢失的数据。

持久化的一些说明

  • 每次调用RDD的一个新的行动操作(action)时,都会从头开始计算RDD,为了减少计算量,我们可以对中间结果进行持久化。

常用的RDD转化与行动操作

针对各个元素的转化操作
  • map:将一个函数应用于集合中的每个元素,将函数的返回结果作为结果RDD中的对应的值
  • filter:接受一个函数,将RDD中所有满足该函数的元素放入新的RDD中并返回。

    nums = sc.parallelize([1,2,3,4])
    mapRDD = nums.map( lambda x :x*x )
    squared = mapRDD.collect()
    for num in squared:
        print( num )
    filterRDD = nums.filter( lambda x : x>2 )
    for num in filterRDD.collect():
        print( num )
    
  • flatmap:对于输入RDD中的每个元素,会输出多个元素,最终将所有的输出元素放入新的RDD中并返回,这个最常用的就是在单词个数统计等任务中,即将文本中所有行的文本信息拆分为单词,然后再放入RDD中

    lines = sc.parallelize(["hello world", "hi"])
    words = lines.flatMap( lambda line : line.split(" ") )
    print( words.count() )
    print( words.first() )
    
伪集合操作
  • RDD对象虽然不是严格意义上的集合,但它支持一些基本的集合操作。RDD集合不具有唯一性,即RDD中的几何可能包含重复元素。针对这种现象,可以通过distinct操作去除重复元素,但是需要注意:这个函数的开销很大,因为它需要对所有网络数据进行数据混洗,因此尽量避免使用

    lines = sc.parallelize(["hello", "hi", "hello"])
    disLines = lines.distinct()
    print( lines.count() )
    print( disLines.count() )
    
  • union:将两个RDD进行合并,但是对于2个RDD中包含的相同的元素,生成的RDD会包含这些重复数据,即它不包含数据混洗的操作,因此如果有必要的话,需要通过其他方法进行去除。

  • intersection:找出2个RDD中相同的元素,重复的数据只会被计算一次,这会进行数据混洗,因此开销也很大

    lines1 = sc.parallelize(["hello", "hi", "hello"])
    lines2 = sc.parallelize(["hi", "test"])
    ret = lines1.intersection( lines2 )
    print( ret.count() )
    
  • subtract:返回一个只存在于第一个RDD中耳不在第二个RDD中的所有元素组成的RDD,这也会进行数据混洗
  • cartesian:求2个RDD的笛卡尔积,即返回所有的(a,b)的tuple,这个函数开销巨大。

行动操作

  • reduce:接收一个函数作为参数,操作2个相同元素类型的RDD数据,并返回一个同类型的新元素
  • fold:将RDD中的所有元素聚合为1个元素,它接收一个初始值参与计算,如果是加法,就是0,乘法的话,就是1。
  • reduce与fold的返回值类型与RDD的元素类型都是相同的。
  • aggregate:它可以实现返回与RDD对象元素类型不同的元素类型,但是需要提供期待返回的类型的初始值,然后通过一个函数将RDD中的元素合并起来放入累加器。因为可能涉及到不同累加器之间的合并,因此需要提供一个函数将累加器之间两两合并。

    # 求平均数
    nums = sc.parallelize( range(1,10) )
    sumCnt = nums.aggregate((0,0), 
                        (lambda acc, value : (acc[0]+value, acc[1]+1)),
                        (lambda acc1, acc2: (acc1[0]+acc2[0], acc1[1]+acc2[1])))
    avg = sumCnt[0] / float(sumCnt[1])
    print( avg )
    
  • collect:取出RDD中的所有元素,注意:这常常用于测试,在使用中,需要保证RDD中的所有对象能够一同被放入内存中
  • take:接受一个数作为输入,返回这么多元素的对象列表,返回的顺序可能之前在RDD中的顺序不一样。

注意

  • 有些转换的操作是专门针对的数值型RDD,有些是专门针对key-value型RDD,各有不同
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

littletomatodonkey

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值