【Spark Core】RDD的创建

目录

1、PySpark中创建RDD的方式

2、并行化方式创建RDD

3、小文件读取

4、通过外部数据创建RDD

5、扩展:RDD分区数


1、PySpark中创建RDD的方式

  • 并行化本地集合:sc.parallelize(data, numSlices)

  • 读取外部文件数据:sc.textFile(name, minPartitions)

  • 读取外部小文件数据:sc.wholeTextFile(path, minPartitions)

引言

官方文档: http://spark.apache.org/docs/latest/rdd-programming-guide.html#resilient-distributed-datasets-rdds

如何将数据封装到RDD集合中,主要有两种方式:

并行化本地集合(Driver Program中)和引用加载外部存储系统(如HDFS、Hive、HBase、Kafka、Elasticsearch等

1、通过 textFile(data): 通过读取外部文件的方式来初始化RDD对象,实际工作中经常使用。

2、通过 parallelize(data): 通过自定义列表的方式初始化RDD对象。(一般用于测试)

(1)第一步 创建sparkContext

SparkContext:Spark程序的入口. SparkContext代表了和Spark集群的链接, 在Spark集群中通过SparkContext来创建RDD

SparkConf:创建SparkContext的时候需要一个SparkConf, 用来传递Spark应用的基本信息。

conf = SparkConf().setAppName(appName).setMaster(master)

sc = SparkContext(conf=conf)

在pyspark shell中 已经为我们创建好了 SparkContext 通过sc直接使用 可以在spark UI中看到当前的Spark作业 在浏览器访问当前centos的4040端口 192.168.88.161:4040 

2、并行化方式创建RDD

首先Spark官网针对创建方式的说明:

调用`SparkContext`的 `parallelize` 方法并且传入已有的可迭代对象或者集合:

>>> data = [1, 2, 3, 4, 5]

>>> distData = sc.parallelize(data)

>>> data   [1, 2, 3, 4, 5]也可以在spark ui中观察执行情况

在通过parallelize方法创建RDD 的时候可以指定分区数量

>>> distData = sc.parallelize(data,5)

>>> distData.reduce(lambda a, b: a + b)

15 


 

from pyspark import SparkContext, SparkConf

import os

os.environ['SPARK_HOME'] = '/export/servers/spark'

PYSPARK_PYTHON = "/root/anaconda3/envs/pyspark_env/bin/python"

# 当存在多个版本时,不指定很可能会导致出错

os.environ["PYSPARK_PYTHON"] = PYSPARK_PYTHON os.environ["PYSPARK_DRIVER_PYTHON"] = PYSPARK_PYTHON

if __name__ == '__main__':

    print('PySpark First Program')

    # 输入数据

    data = ["hello", "world", "hello", "world"]

    conf = SparkConf().setAppName("miniProject").setMaster("local[*]")

    # sc = SparkContext.getOrCreate(conf)

    sc = SparkContext(conf=conf)

    # 将collection的data转为spark中的rdd并进行操作

    rdd = sc.parallelize(data)

    # 执行map转化操作以及reduceByKey的聚合操作

    res_rdd = rdd.map(lambda word: (word, 1)).reduceByKey(lambda a, b: a + b)

    # 将rdd转为collection并打印

    res_rdd_coll = res_rdd.collect()

    for line in res_rdd_coll:

        print(line)

    print('停止 PySpark SparkSession 对象')

    sc.stop()

3、小文件读取

在实际项目中,有时往往处理的数据文件属于小文件(每个文件数据数据量很小,比如KB,几十MB等),文件数量又很大,如果一个个文件读取为RDD的一个个分区,计算数据时很耗时性能低下,使用SparkContext中提供:wholeTextFiles类,专门读取小文件数据。

范例演示:

读取100个小文件rating数据,每个文件大小小于1MB,查看默认情况下分区个数情况

# -*- coding: utf-8 -*-
from pyspark import SparkContext, SparkConf
import os
os.environ['SPARK_HOME'] = '/export/servers/spark'
PYSPARK_PYTHON = "/root/anaconda3/envs/pyspark_env/bin/python"
# 当存在多个版本时,不指定很可能会导致出错
os.environ["PYSPARK_PYTHON"] = PYSPARK_PYTHON
os.environ["PYSPARK_DRIVER_PYTHON"] = PYSPARK_PYTHON
if __name__ == '__main__':
    print('PySpark WholeTextFile Program')
    # TODO:1、创建应用程序入口SparkContext实例对象
    conf = SparkConf().setAppName("miniProject").setMaster("local[*]")
    sc = SparkContext.getOrCreate(conf)
    # TODO: 2、从文件系统加载数据,调用textFile
    resultRDD1 = sc.textFile("file:///export/pyfolder1/pyspark-chapter02_3.8/data/ratings100/")
    # TODO: 3、调用集合RDD中函数处理分析数据,调用wholeTextFiles
    resultRDD2 = sc.wholeTextFiles("file:///export/pyfolder1/pyspark-chapter02_3.8/data/ratings100/")
    # TODO: 4、获取分区数
    print("textFile numpartitions:", resultRDD1.getNumPartitions())
    print("whole textFile numpartitions:", resultRDD2.getNumPartitions())
    # print(resultRDD2.take(2))
    print('停止 PySpark SparkSession 对象')
    # 关闭SparkContext
    sc.stop()

4、通过外部数据创建RDD

1、PySpark可以从Hadoop支持的任何存储源创建RDD,包括本地文件系统,HDFSCassandra,HBase,Amazon S3等。

2、支持整个目录、多文件、通配符

3、支持压缩文件

如下为Spark官网描述的支持文件信息: 

>>> rdd1 = sc.textFile('file:///root/tmp/word.txt')

>>> rdd1.collect()

['foo foo quux labs foo bar quux abc bar see you by test welcome test', 'abc labs foo me python hadoop ab ac bc bec python'] 

from pyspark import SparkContext, SparkConf
import os
import re
os.environ['SPARK_HOME'] = '/export/servers/spark'
PYSPARK_PYTHON = "/root/anaconda3/envs/pyspark_env/bin/python"
# 当存在多个版本时,不指定很可能会导致出错
os.environ["PYSPARK_PYTHON"] = PYSPARK_PYTHON
os.environ["PYSPARK_DRIVER_PYTHON"] = PYSPARK_PYTHON
if __name__ == '__main__':
    print('PySpark RDD Program')
    data = ["hello", "world", "hello", "world"]
    # TODO:1、创建应用程序入口SparkContext实例对象
    conf = SparkConf().setAppName("miniProject").setMaster("local[*]")
    sc = SparkContext.getOrCreate(conf)
    # TODO: 2、从文件系统加载数据,创建RDD数据集
    # TODO: 3、调用集合RDD中函数处理分析数据
    resultRDD2 = sc.textFile("file:///export/pyfolder1/pyspark-chapter02_3.8/data/word.txt") \
        .flatMap(lambda line: re.split("\s+", line)) \
        .map(lambda x: (x, 1)) \
        .reduceByKey(lambda a, b: a + b)
    # TODO: 4、保存结果RDD到外部存储系统(HDFS、MySQL、HBase。。。。)
    res_rdd_coll = resultRDD2.collect()
    for line in res_rdd_coll:
        print(line)
    print('停止 PySpark SparkSession 对象')
    # 关闭SparkContext
    sc.stop()

5、扩展:RDD分区数

在描述RDD 属性时,多次提到了分区(partition)的概念。分区是一个偏物理层的概念,也是 RDD 并行计算的单位。 数据在 RDD 内部被切分为多个子集合,每个子集合可以被认为是一个分区,运算逻辑最小会被应用在每一个分区上,每个分区是由一个单独的任务(task)来运行的,所以分区数越多,整个应用的并行度也会越高。 获取RDD分区数目方式,如下:

http://spark.apache.org/docs/latest/api/python/reference/api/pyspark.RDD.getNumPartitions.html#pyspark.RDD.getNumPartitions bin/pyspark --master local[2]

>>> data = [1, 2, 3, 4, 5]

>>> distData = sc.parallelize(data)

>>> distData.getNumPartitions()  #2 

 RDD分区的数据取决于哪些因素?

第一点:RDD分区的原则是使得分区的个数尽量等于集群中的CPU核心(core)数目,这样可以充分利用CPU的计算资源;

第二点:在实际中为了更加充分的压榨CPU的计算资源,会把并行度设置为cpu核数的2~3倍;

第三点:RDD分区数和启动时指定的核数、调用方法时指定的分区数、如文件本身分区数有关系,具体如下说明:

1)、启动的时候指定的CPU核数确定了一个参数值:

spark.default.parallelism=指定的CPU核数(集群模式最小2)

思考:尝试spark.default.parallelism设置小一些,查看分区数

2)、对于Scala集合调用parallelize(集合,分区数)方法

如果没有指定分区数,就使用spark.default.parallelism

如果指定了就使用指定的分区数(建议不要指定大于spark.default.parallelism)

3)、对于textFile(文件, 分区数)

defaultMinPartitions

如果没有指定分区数sc.defaultMinPartitions=min(defaultParallelism,2)

如果指定了就使用指定的分区数sc.defaultMinPartitions=指定的分区数rdd的分区数

rdd的分区数

对于本地文件

rdd的分区数 = max(本地file的分片数,sc.defaultMinPartitions)

注意:这里即便自定义设置分区个数也不行,如sc.textFile(“”,3)

对于HDFS文件

rdd的分区数 = max(hdfs文件的block数目, sc.defaultMinPartitions)

所以如果分配的核数为多个,且从文件中读取数据创建RDD,即使hdfs文件只有1个切片,最后的Spark的RDD的partition数也有可能是2

总结:

  • RDD分区数量(线程数量)一般设置为CPU核心数的2~3倍

  • RDD分区数量有多个原因:调用任务时设置CPU核心数,调用API可以设置分区数量,读取文件数据的文件的数量

  • 当初始化SparkContext时,取决于spark.default.parallelism的值

    • 本地:spark.default.parallelism取决于local[N]中N为多少,并行度就是多少

    • 集群:spark.default.parallelism至少为2

  • 创建RDD时

    • 并行化本地创建:sc.parallelize(data, numSlices)

      • 如果没有指定分区数numSlices,分区数量取决于spark.default.parallelism

      • 如果设置了分区数numSlices,以你设置的分区数为准

    • 读取外部文件:sc.textFile(name, minPartition)

      • 分区数量首先取决于defaultMinPartion的值

        • 如果指定了minPartition,defaultMinPartition就等于minPartition

        • 如果没有指定minPartition,defaultMinPartition就等于min(spark.default.parallelism, 2)

      • 分区数量最终确定

        • 当读取本地文件时:RDD分区数=max(本地文件分片数, defaultMinPartition)

        • 当读取HDFS文件时:RDD分区数=max(文件的block块数, defaultMinPartition

  • 38
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值