• 第2天Python实战Spark大数据分析及调度-RDD编程


    Spark提供的主要抽象是resilient distributed dataset(RDD) 弹性分布式数据集,它是跨集群节点划分的元素的集合,可以并行操作。通过从Hadoop文件系统(或任何其他Hadoop支持的文件系统)中的文件或驱动程序中现有的Scala集合开始并进行转换来创建RDD。用户还可以要求SparkRDD 保留在内存中,以使其能够在并行操作中有效地重用。最后,RDD自动从节点故障中恢复。

    Spark中的第二个抽象是可以在并行操作中使用的共享变量。默认情况下,当Spark作为一组任务在不同节点上并行运行一个函数时,它会将函数中使用的每个变量的副本传送给每个任务。有时,需要在任务之间或任务与驱动程序之间共享变量。Spark支持两种类型的共享变量:广播变量(可用于在所有节点上的内存中缓存值)和累加器(accumulator),这些变量仅被“添加”到其上,例如计数器和总和

    RDD五大特性

    • A list of partitions

        一组分区:RDD由很多partition构成,有多少partition就对应有多少task

    • A function for computing each split

        一个函数:对RDD做计算,相当于对RDD的每个split或partition做计算

    • A list of dependencies on other RDDs

        RDD之间有依赖关系,可溯源

    • Optionally, a Partitioner for key-value RDDs (e.g. to say that the RDD is hash-partitioned)

        一个Partitioner:即RDD的分片函数,如果RDD里面存的数据是key-value形式,则可以传递一个自定义的Partitioner进行重新分区

    • Optionally, a list of preferred locations to compute each split on (e.g. block locations for an HDFS file)

        一个列表:存储存取每个Partition的优先位置(preferred location),计算每个split时,在split所在机器的本地上运行task是最好的,避免了数据的移动,split有多个副本,所以preferred location不止一个

    初始化Spark

    Spark程序做的第一件事情就是创建一个SparkContext对象,该对象告诉Spark如何访问集群,要创建一个SparkContext首先需要构建一个SparkConf对象,其中包含应用程序程序的信息

    from pyspark import SparkConf, SparkContext
    conf
    = SparkConf().setAppName(appName).setMaster(master) sc = SparkContext(conf=conf)

    # 业务逻辑

    sc.stop()

    appName参数是应用程序显示在集群UI上的名称

    master是Spark,Mesos或YARN群集URL或特殊的“本地”字符串,以本地模式运行

    当在集群上运行时,您将不希望master在程序中进行硬编码,而是在其中启动应用程序spark-submit并在其中接收。但是,对于本地测试和单元测试,您可以传递“ local”以在内部运行Spark

    注意:

      在PySpark Shell中,已经为我们初始化了Spark, 变量为sc, 我们自己配置的SparkContext将不起作用,也就是我们自己不用再初始化了

    创建RDD的两种方式

    方式一:  通过现有的可迭代对象或集合调用SparkContextparallelize创建

    data = [1, 2, 3, 4, 5]
    rdd = sc.parallelize(data)

    创建rdd后可以并行操作。例如调用distData.reduce(lambda a, b: a + b)计算集合元素的和

    >>> rdd.reduce(lambda a,b: a+b)
    15

    并行集合的一个重要参数就是将数据集切入分区,Spark将为集群的每个分区运行一个任务。通常,群集中的每个CPU都需要2-4个分区。通常,Spark会尝试根据您的集群自动设置分区数。但是,您也可以通过将其作为第二个参数传递给parallelize(例如sc.parallelize(data, 10))来手动设置它。

    方式二: 外部数据集

    PySpark可以从Hadoop支持的任何存储源创建分布式数据集,包括您的本地文件系统,HDFSCassandraHBaseAmazon S3等。Spark支持文本文件,SequenceFiles和任何其他Hadoop InputFormat

    可以使用SparkContexttextFile方法创建文本文件RDD 。此方法需要一个URI的文件(本地路径的机器上,或一个hdfs://s3a://等URI),并读取其作为行的集合。这是一个示例调用:

    rdd = sc.textFile("data.txt")

    RDD操作

    RDD支持两种类型操作:

    1.  transformation(转换): create a new dataset from an existing one 从现有的数据集中创建新数据集
    2.  action(动作): return a value to the driver program after running a conputation on the dataset  对数据集执行计算后,将值返回给驱动程序

    常用的transformation

    map(func)

    将func函数作用到数据集的每一个元素上,生成一个新的分布式的数据集返回

    from pyspark import SparkConf, SparkContext
    
    
    if __name__ == '__main__':
        conf = SparkConf()
        sc = SparkContext(conf=conf)
    
    
        def my_map1():
            data = [1, 2, 3, 4, 5, 6]
            rdd1 = sc.parallelize(data)
            rdd2 = rdd1.map(lambda x: x + 1)
            print(rdd2.collect())
    
    
        def my_map2():
            rdd1 = sc.parallelize(["java", "python", "php", "ruby"])
            rdd2 = rdd1.map(lambda x: (x, len(x)))
            print(rdd2.collect())
    
        my_map1()
        my_map2()
        
        sc.stop()
    
    
    # 输出结果
    [2, 3, 4, 5, 6, 7]
    [('java', 4), ('python', 6), ('php', 3), ('ruby', 4)]
    map示例

    filter(func)

    选出所有func返回值为true的元素,生成一个新的分布式的数据集返回

    from pyspark import SparkConf, SparkContext
    
    
    if __name__ == '__main__':
        conf = SparkConf()
        sc = SparkContext(conf=conf)
    
        def my_filter():
            data = [1, 2, 3, 4, 5]
            rdd = sc.parallelize(data)
            rddMap = rdd.map(lambda x: x * 2)
            rddFilter = rddMap.filter(lambda x: x > 6)
            print(rddFilter.collect())
    
        def my_filter02():
            # 使用链式写法优化代码
            data = [1, 2, 3, 4, 5]
            print(sc.parallelize(data).map(lambda x: x * 2).filter(lambda x: x > 6).collect())
            
        my_filter()
    
        sc.stop()
    
    
    # 输出结果
    [8, 10]
    filter示例

    flatMap(func)

    输入的item能够被map到0或者多个items输出,返回值是一个Sequence

    from pyspark import SparkConf, SparkContext
    
    
    if __name__ == '__main__':
        conf = SparkConf()
        sc = SparkContext(conf=conf)
    
        def my_flatMap():
            data = ["hello heboan", "hello python", "world ok"]
            rdd = sc.parallelize(data)
            print(rdd.flatMap(lambda line: line.split(" ")).collect())
    
        my_flatMap()
    
        sc.stop()
    
    
    # 输出结果
    ['hello', 'heboan', 'hello', 'python', 'world', 'ok']
    flatMap示例

    groupBykey()

    把相同的key的数据分发到一起

    from pyspark import SparkConf, SparkContext
    
    
    if __name__ == '__main__':
        conf = SparkConf()
        sc = SparkContext(conf=conf)
    
        def my_groupByKey():
            data = ["hello heboan", "hello python", "hello world"]
            # key ==> (key, 1)
            rddMap = sc.parallelize(data).flatMap(lambda line: line.split(" ")).map(lambda x: (x, 1))
            # print(rddMap.collect())
            rdd_groupByKey = rddMap.groupByKey()
            # print(rdd_groupByKey.collect())
            print(rdd_groupByKey.map(lambda x: (x[0], list(x[1]))).collect())
    
        my_groupByKey()
    
        sc.stop()
    
    
    # 输出结果
     [('python', [1]), ('heboan', [1]), ('hello', [1, 1, 1]), ('world', [1])]
    groupByKey示例

    reduceByKey(func)

    from pyspark import SparkConf, SparkContext
    
    
    if __name__ == '__main__':
        conf = SparkConf()
        sc = SparkContext(conf=conf)
    
        def my_reduceMap():
            data = ["hello heboan", "hello python", "hello world"]
            rddMap = sc.parallelize(data).flatMap(lambda line: line.split(" ")).map(lambda x: (x, 1))
            rdd_reduceByKey = rddMap.reduceByKey(lambda a, b: a + b)  # 相邻的数相加
            print(rdd_reduceByKey.collect())
    
        my_reduceMap()
    
        sc.stop()
    
    
    # 输出结果
    [('python', 1), ('heboan', 1), ('hello', 3), ('world', 1)]
    reduceMap示例

    sortByKey()

    排序

    from pyspark import SparkConf, SparkContext
    
    
    if __name__ == '__main__':
        conf = SparkConf()
        sc = SparkContext(conf=conf)
    
        def my_sortByKey():
            data = ["hello heboan", "hello python", "hello world"]
            rddMap = sc.parallelize(data).flatMap(lambda line: line.split(" ")).map(lambda x: (x, 1))
            rdd_reduceByKey = rddMap.reduceByKey(lambda a, b: a + b)
            # 因为sortByKey是对key记性排序的,所以先使用map调换k,v的位置进行排序,传入False表示降序,排序完成后再把k,v位置换回来
            rdd_sortByKey = rdd_reduceByKey.map(lambda x:(x[1],x[0])).sortByKey(False).map(lambda x:(x[1],x[0]))
            print(rdd_sortByKey.collect())
    
        my_sortByKey()
    
        sc.stop()
    
    
    # 输出结果
    [('hello', 3), ('python', 1), ('heboan', 1), ('world', 1)]
    sortByKey示例

    union()

    就是两个数据集合并

    from pyspark import SparkConf, SparkContext
    
    
    if __name__ == '__main__':
        conf = SparkConf()
        sc = SparkContext(conf=conf)
    
        def my_union():
            a = sc.parallelize([1, 2, 3])
            b = sc.parallelize([4, 5, 6])
            print(a.union(b).collect())
    
        my_union()
    
        sc.stop()
    
    
    # 输出结果
    [1, 2, 3, 4, 5, 6]
    union示例

    distinct()

    去重

    from pyspark import SparkConf, SparkContext
    
    
    if __name__ == '__main__':
        conf = SparkConf()
        sc = SparkContext(conf=conf)
    
        def my_distinct():
            a = sc.parallelize([1, 2, 3])
            b = sc.parallelize([3, 4, 5])
            print(a.union(b).distinct().collect())
    
        my_distinct()
    
        sc.stop()
    
    
    # 输出结果
    [1, 2, 3, 4, 5]
    distinct示例

    join()

    from pyspark import SparkConf, SparkContext
    
    
    if __name__ == '__main__':
        conf = SparkConf()
        sc = SparkContext(conf=conf)
    
        def my_join():
            a = sc.parallelize([("A", "a1"), ("B", "b1"), ("C", "c1"), ("D", "d1")])
            b = sc.parallelize([("A", "a2"), ("C", "c2"), ("F", "f1")])
            print(a.join(b).collect())
            print(a.leftOuterJoin(b).collect())
            print(a.rightOuterJoin(b).collect())
            print(a.fullOuterJoin(b).collect())
    
        my_join()
    
        sc.stop()
    
    
    # 输出结果
    [('C', ('c1', 'c2')), ('A', ('a1', 'a2'))]
    [('B', ('b1', None)), ('D', ('d1', None)), ('C', ('c1', 'c2')), ('A', ('a1', 'a2'))]
    [('F', (None, 'f1')), ('C', ('c1', 'c2')), ('A', ('a1', 'a2'))]
    [('F', (None, 'f1')), ('B', ('b1', None)), ('D', ('d1', None)), ('C', ('c1', 'c2')), ('A', ('a1', 'a2'))]
    join示例

    常用action

    collect
    count
    take
    reduce
    foreach
    saveAsTextFile
    max
    min
    sum

    from pyspark import SparkConf, SparkContext
    
    
    if __name__ == '__main__':
        conf = SparkConf()
        sc = SparkContext(conf=conf)
    
    
        def my_action():
            data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
            rdd = sc.parallelize(data)
            print(rdd.collect())  # 输出
            print(rdd.count())  # 计数
            print(rdd.take(3))  # 前3个元素
            print(rdd.max())  # 最大的元素
            print(rdd.sum())  # 所有元素之和
            print(rdd.reduce(lambda a, b: a + b))  # 求和
            rdd.foreach(lambda x: print(x))  # 输出每个元素
            rdd.saveAsTextFile("hdfs://heboan-hadoop-000:8020/tmp")  # 写入到文件系统
    
        my_action()
    
        sc.stop()

    实战案例---词频统计

    hello word
    hello heboan
    my name is heboan
    hello everyone
    heboan.txt
    # /data/script/wc.py
    
    from pyspark import SparkConf, SparkContext
    import sys
    
    
    if __name__ == '__main__':
        if len(sys.argv) != 2:
            print("Usage: wordcount <input>", file=sys.stderr)
            sys.exit(-1)
    
        conf = SparkConf()
        sc = SparkContext(conf=conf)
    
        rdd = sc.textFile(sys.argv[1])
            .flatMap(lambda line: line.split(" "))
            .map(lambda x: (x, 1)).reduceByKey(lambda a, b: a+b)
    
        for word, count in rdd.collect():
            print("{}: {}".format(word, count))
    
        sc.stop()

    服务器执行

    [root@heboan-hadoop-000 ~]# spark-submit --master local[2] --name heboan001 /data/script/wc.py file:///root/heboan.txt

    >>>>>>>延伸

    上面我们是指定了一个文件/root/heboan.txt, 我们也可以指定一个目录

    # /root/data/目录下的所有文件都会进行计算
    spark-submit --master local[2] --name heboan001 /data/script/wc.py file:///root/data/

    计算特定的文件,如

    # /root/data/目录下的所有.txt后缀文件都会进行计算
    spark-submit --master local[2] --name heboan001 /data/script/wc.py file:///root/data/*.txt

    案例实战----网站访问ip前5

    案例实战---统计平均年龄

  • 相关阅读:
    Netty源码分析-ChannelPipeline事件传播
    Netty源码分析-NioEventLoop事件轮询
    Netty源码分析-ServerBootstrap启动过程
    Canal基本原理
    [Android]proguard重新编译和如何不混淆第三方jar包
    [Android]listview recycleview的复用问题
    [Android] android .keystore文件转x509pem工具
    [Android] android studio 2.0即时运行功能探秘
    大神都是有个起点的
    Python列表的用法和基本操作
  • 原文地址:https://www.cnblogs.com/sellsa/p/13019123.html
Copyright © 2020-2023  润新知