Spark

1. 前言介绍

1.1 spark是什么?

定义:Apache Spark是用于大规模数据(large-scala data)处理的统一(unified)分析引擎

在这里插入图片描述

简单来说,Spark是一款分布式的计算框架,用于调度成百上千的服务器集群,计算TB、PB乃至EB级别的海量数据

在这里插入图片描述

Python on Spark

Spark作为全球顶级的分布式计算框架,支持众多的编程语言进行开发而Python语言,则是Spark重点支持的方向

PySpark

Spark对Python语言的支持,重点体现在Python第三方库:PySpark之上

PySpark是由Spark官方开发的Python语言第三方库

Python开发者可以使用pip程序快速的安装PySpark并像其它三方库那样直接使用

在这里插入图片描述

  • PySpark是Spark的Python实现,是Spark为Python开发者提供的编程入口用于以Python代码完成Spark任务的开发
  • PySpark不仅可以作为Python第三方库使用,也可以将程序提交的Spark集群环境中,调度大规模集群进行执行

1.2 为什们要学习 PySpark?

Python应用场景和就业方向是十分丰富的,其中,最为亮点的方向为:大数据开发人工智能

在这里插入图片描述

大数据开发是Python众多就业方向中的明星赛道,薪资高岗位多,Spark(PySpark)又是大数据开发中的核心技术

2. 基础准备

2.1 PySpark 库的安装

同其它的 Python 第三方库一样,PySpark 同样可以使用 pip 程序进行安装

  • 在 ”CMD” 命令提示符程序内,输入:
    • pip install pyspark
  • 或使用国内代理镜像网站(清华大学源)
    • pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyspark

在这里插入图片描述

2.2 构建 PySpark 执行环境入口对象

想要使用 PySpark 库完成数据处理,首先需要构建一个执行环境入口对象

PySpark的执行环境入口对象是:类 SparkContext 的类对象

#导包
from pyspark import SparkConf, SparkContext
#创建SparkConf类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")
#基于SparkConf类对象创建SparkContext对象
sc = SparkContext(conf = conf)
#打印PySpark的运行版本
print(sc.version)
#停止SparkContext对象的运行(停止PySpark程序)
sc.stop()

运行结果如下,可以看出主机安装的 PySpark 版本号

在这里插入图片描述

2.3 PySpark 的编程模型

SparkContext类对象,是PySpark编程中一切功能的入口

PySpark 的编程,主要分为如下三大步骤:

在这里插入图片描述

  • 通过SparkContext对象,完成数据输入
  • 输入数据后得到RDD对象,对RDD对象进行迭代计算
  • 最终通过RDD对象的成员方法,完成数据输出工作

在这里插入图片描述

3. 数据输入

3.1 RDD 对象

如图可见,PySpark 支持多种数据的输入,在输入完成后,都会得到一个:RDD 类的对象

RDD 全称为:弹性分布式数据集(Resilient Distributed Datasets)

PySpark 针对数据的处理,都是以 RDD 对象作为载体,即:

  • 数据存储在 RDD 内
  • 各类数据的计算方法,也都是 RDD 的成员方法
  • RDD的数据计算方法,返回值依旧是 RDD 对象

在这里插入图片描述

3.2 Python 数据容器转 RDD 对象

PySpark支持通过 SparkContext 对象的 parallelize 成员方法,将list / tuple / set / dict / str 转换为 PySpark 的 RDD 对象

# 导包
from pyspark import SparkConf, SparkContext

# 创建SparkConf类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")

# 基于SparkConf类对象创建SparkContext对象
sc = SparkContext(conf=conf)

# 通过paralLelize方法将Python对象加载到Spark内,成为RDD对象
rdd1 = sc.parallelize([1, 2, 3, 4, 5]) # list
rdd2 = sc.parallelize((1, 2, 3, 4, 5)) # tuple
rdd3 = sc.parallelize("abcde") # str
rdd4 = sc.parallelize({1, 2, 3, 4, 5}) # set
rdd5 = sc.parallelize({"key1": "value1", "key2": "value2"}) # dirt

# 打印 如果要查看RDD里面有什么内容,需要用collect()方法
print(rdd1.collect())
print(rdd2.collect())
print(rdd3.collect())
print(rdd4.collect())
print(rdd5.collect())

# 停止SparkContext对象的运行(停止PySpark程序)
sc.stop()

运行结果如下,特殊的是,字典只存入 key, value没有被存入;字符串会被拆开然后存入 RDD 中

在这里插入图片描述

注意:

  • 字符串会被拆分出1个个的字符,存入 RDD 对象
  • 字典仅有 key 会被存入 RDD 对象

3.3 读取文件转 RDD 对象

PySpark 也支持通过 SparkContext 入口对象,来读取文件,来构建出 RDD 对象

# 导包
from pyspark import SparkConf, SparkContext

# 创建SparkConf类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")

# 基于SparkConf类对象创建SparkContext对象
sc = SparkContext(conf=conf)

# 用过textFile方法,读取文件数据加载到Spark内,成为RDD对象
rdd = sc.textFile("hello.txt")
print(rdd.collect())

# 停止SparkContext对象的运行(停止PySpark程序)
sc.stop()

运行结果如下,很明显 hello.txt 文件中的信息被存入到了 RDD 对象中

在这里插入图片描述

hello.txt 文件信息如下图,

在这里插入图片描述

总结:如何输入数据到 Spark (即得到 RDD 对象)

  • 通过SparkContext的parallelize成员方法,将 Python 数据容器转换为 RDD 对象
  • 通过SparkContext的textFile成员方法读取文本文件得到 RDD 对象

4. 数据计算

PySpark 的数据计算,都是基于 RDD 对象来进行的,那么如何进行呢?

自然是依赖 RDD 对象内置丰富的:成员方法(算子)

4.1 map方法

map 算子

  • 功能:map 算子是将 RDD 的数据一条条处理(处理的逻基于 map 算子中接收的处理函数),返回新的 RDD

  • 语法:

    rdd .map(func)
    # func :   f: (T) -> U
    # f: 表示这是一个函数(方法)
    #(T) -> U 表示的是方法的定义:
    # () 表示传入参数, (T) 表示 传入1个参数,()表示没有传入参数#
    # T 是泛型的代称,在这里表示任意类型
    # U 也是泛型代称,在这里表示任意类型
    # -> U 表示返回值
    # (T) -> U 总结起来的意思是:
    #      这是一个方法,这个方法接受一个参数传入,传入参数类型不限返回一个返回值,返回值类型不限
    # (A) -> A 总结起来的意思是:
    #      这是一个方法,这个方法接受一个参数传入,传入参数类型不限返回一个返回值,返回值和传入参数类型一致
    

通过在 PyCharm 中调用 map 方法,可以看到需要传入一个函数,且这个函数需要满足能够接收一个参数的传入,可以返回一个返回值

在这里插入图片描述

因此,我们自己定义了一个传入一个参数且有返回值的函数

# 通过map方法将全部数据都乘以10
def func(data):
    return data * 10

我们把自己定义的 func 函数当作参数传入 map 方法中,此时的 map 方法的含义很简单,就是把 RDD 对象中的每一个数据都调用 func 这个函数进行处理,从而得到新的 RDD 对象

然后通过上面所学的知识,我们利用 collect 方法查看新的 RDD 对象中的内容,编译器报错

# 导包
from pyspark import SparkConf, SparkContext

# 创建SparkConf类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")

# 基于SparkConf类对象创建SparkContext对象
sc = SparkContext(conf = conf)

# 准备一个RDD
# 通过paralLelize方法将Python对象加载到Spark内,成为RDD对象
rdd = sc.parallelize([1, 2, 3, 4, 5])

# 通过map方法将全部数据都乘以10
def func(data):
    return data * 10

# 通过利用 map方法将之前 RDD 对象中的数据进行处理后得到新的 RDD 对象
rdd2 = rdd .map(func)

# 打印 如果要查看RDD里面有什么内容,需要用collect()方法
print(rdd2.collect())

# 停止SparkContext对象的运行(停止PySpark程序)
sc.stop()

报错如下图,

在这里插入图片描述

根据代码报错提示,可以清楚的看到 Spark 没有找到主机配置的 Python 解释器,但为什么我们明明已经配置好了 Python 解释器这里却仍然报错呢?其实,我们配置的 Python 解释器只是让 PyCharm 识别了我们的 Python 解释器,当 Spark 运行起来时,基于 Spark 本质上是一个分布式的程序,内部的运行机制较为复杂,这里报错的原因是 Spark 没有识别到我们的 Python 解释器

如何解决这个问题呢?我们只需在 Spark 中手动设置一个环境变量,明确告诉 Spark 主机的 Python所在的位置就可以解决这个问题

import os
# 值指向电脑 Python 解释器所在位置即可
os.environ['PYSPARK_PYTHON'] = "D:\python\python3.11.1\python.exe"

加入如上代码,代码成功运行,结果如下,

在这里插入图片描述

仔细观察所写代码,仍然可以优化,上面我们自己定义的函数非常的简单,他的核心逻辑只有 data * 10 一行,对于简单的函数我们可以采用简单的写法——利用 lambda 表达式写一个匿名类型,根据之前所学知识,我们还可以利用链式调用将简单的计算进行处理

# 链式调用
rdd = rdd.map(func).map(lambda x: x + 10)

4.2 flatMap方法

和 map 的核心功能一样,flatmap 也将 RDD 对象进行处理,生成新的 RDD 对象,唯一不同的是,flatmap 会进行解嵌套

flatMap 算子

  • 功能:对 rdd 执行 map 操作,然后进行解除嵌套操作

  • 解除嵌套:

    # 嵌套的List
    lst = [[123][456][789]]
    
    #如果解除了嵌套
    lst = [123456789]
    
  • 演示代码:

    # coding:utf8
    # 演示rdd的flatMap算子
    from pyspark import SparkConf, SparkContext
    
    if __name__ = '__main__':
    # 0.构建Spark执行环境
        conf = SparkConf().setAppName("create rdd").
        setMaster("local[*]")
        sc = SparkContext(conf = conf)
        rdd = sc.parallelize(["a b c","a c e","e c a"])
        
        #按照空格切分数据后,解除嵌套
        print(rdd.flatMap(lambda x: x.split("")).collect())
    

使用 map 算子,代码如下,

# 导包
from pyspark import SparkConf, SparkContext

import os
# 值指向电脑 Python 解释器所在位置即可
os.environ['PYSPARK_PYTHON'] = "D:\python\python3.10.9\python.exe"

# 创建SparkConf类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")

# 基于SparkConf类对象创建SparkContext对象
sc = SparkContext(conf = conf)

# 准备一个RDD
# 通过paralLelize方法将Python对象加载到Spark内,成为RDD对象
rdd = sc.parallelize(["itlzxr python 666", "java itlzxr python", "php java python"])

# 通过利用 flatmap 方法将之前 RDD 对象中的数据进行处理后得到新的 RDD 对象
# 将rdd数据里面的单词一个个提取出来(利用split方法)
rdd2 = rdd.map(lambda x: x.split(" "))

# 打印 如果要查看RDD里面有什么内容,需要用collect()方法
print(rdd2.collect())

# 停止SparkContext对象的运行(停止PySpark程序)
sc.stop()

如果我们只是单纯的利用 spilt 去提取单词会发现单词还是被嵌套在 list 中,RDD 中存放的是每一个 list,运行结果如下,

在这里插入图片描述

要想解除这种嵌套,我们就需要利用 faltmap 算子对 RDD 中的数据进行处理,

即修改为 flatmap 算子,

rdd2 = rdd.flatmap(lambda x: x.split(" "))

运行结果如下,

在这里插入图片描述

4.3 reduceByKey方法

reduceByKey 算子

功能:针对 KV 型 RDD,自动按照 key 分组,然后根据你提供的聚合逻,完成组内数据(value)的聚合操作

用法:

rdd .reduceByKey(func)
# func:(v,v)- v
# 类型和传入要求一致
# 接受2个传入参数(类型要一致),返回一个返回值,

代码:

rdd = sc.parallelize([("a', 1),("a, 1),("b', 1),("b', 1),("b', 1)])
result = rdd.reduceByKey(lambda a, b: a + b)
print(result.collect())

# 结果:
[('b', 3),('a',2)]

注意:

  • reduceByKey 中接收的函数只负责聚合,不理会分组
  • 分组是自动 by key 来分组的

reduceByKey 中的聚合逻辑是

比如,有 [1, 2, 3, 4, 5],然后聚合函数是:lambda a, b: a + b

在这里插入图片描述

利用 reduceByKey 对 RDD 中的数据进行聚合时,需要注意传入参数的数据类型要与返回值的数据类型一致

在这里插入图片描述

代码演示:

# 导包
from pyspark import SparkConf, SparkContext

import os

# 值指向电脑 Python 解释器所在位置即可
os.environ['PYSPARK_PYTHON'] = "D:\python\python3.10.9\python.exe"

# 创建SparkConf类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")

# 基于SparkConf类对象创建SparkContext对象
sc = SparkContext(conf=conf)

# 准备一个RDD
# 通过paralLelize方法将Python对象加载到Spark内,成为RDD对象
rdd = sc.parallelize([('男', 99), ('男', 88), ('女', 99), ('女', 66)])

# 通过利用 reduceByKey 方法将之前 RDD 对象中的数据进行处理后得到新的 RDD 对象
# 求男生和女生两个组的成绩之和
rdd2 = rdd.reduceByKey(lambda a, b: a + b)

# 打印 如果要查看RDD里面有什么内容,需要用collect()方法
print(rdd2.collect())

# 停止SparkContext对象的运行(停止PySpark程序)
sc.stop()

运行结果如下,可以看出 RDD 中的数据根据男女进行分组并进行了聚合相加的处理

在这里插入图片描述

4.4 练习案例1

WordCount案例

使用学习到的内容,完成:

  • 读取文件
  • 统计文件内,单词的出现数量

演示代码:

"""
完成练习案例: 单词计数统计
"""

# 1.构建执行环境入口对象
from pyspark import SparkConf, SparkContext
import os

os.environ["PYSPARK_PYTHON"] = "D:\python\python3.10.9\python.exe"
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")
sc = SparkContext(conf=conf)

# 2.读取数据文件
rdd = sc.textFile("wordcount.txt")

# 3.取出全部单词
word_rdd = rdd.flatMap(lambda a: a.split(" "))

# 4.将所有单词都转换成二元元组,单词为Key,value设置为1
word_with_one_rdd = word_rdd.map(lambda a: (a, 1))

# 5.分组并求和
result_rdd = word_with_one_rdd.reduceByKey(lambda a, b: a + b)

# 6.打印输出结果
print(result_rdd.collect())

wordcount.txt 文件里的内容:

在这里插入图片描述

运行结果如下,

在这里插入图片描述

4.5 filter方法

Filter

功能:过滤想要的数据进行保留

  • 接受一个处理函数,可用 lambda 快速编写
  • 函数对 RDD 数据逐个处理,得到 True 的保留至返回值的 RDD 中

语法:

rdd.filter(func)
# func: (T)- bool 传入1个参数进来随意类型,返回值必须是True or False

返回是 True 的数据被保留,False 的数据被丢弃

示例代码:

"""
演示rdd的filter算子
"""

# 导包
from pyspark import SparkConf, SparkContext

import os

# 值指向电脑 Python 解释器所在位置即可
os.environ['PYSPARK_PYTHON'] = "D:\python\python3.10.9\python.exe"

# 创建SparkConf类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")

# 基于SparkConf类对象创建SparkContext对象
sc = SparkContext(conf=conf)

# 准备一个RDD
# 通过paralLelize方法将Python对象加载到Spark内,成为RDD对象
rdd = sc.parallelize([1, 2, 3, 4, 5])

# 通过利用 filter 方法将之前 RDD 对象中的数据进行处理后得到新的 RDD 对象
# 判断是否为偶数,偶数返回true,奇数false
# 保留偶数
# rdd.filter(lambda x: True if (x % 2 - 1) else False)
rdd2 = rdd.filter(lambda a: a % 2 == 0)

# 打印 如果要查看RDD里面有什么内容,需要用collect()方法
print(rdd2.collect())

# 停止SparkContext对象的运行(停止PySpark程序)
sc.stop()

运行结果如下,1、3、5为奇数被过滤了

在这里插入图片描述

4.6 distinct方法

distinct 算子

功能:对 RDD 数据进行去重返回新 RDD

语法:rdd.distinct() 无需传参

演示代码:

"""
演示rdd的filter算子
"""

# 导包
from pyspark import SparkConf, SparkContext

import os

# 值指向电脑 Python 解释器所在位置即可
os.environ['PYSPARK_PYTHON'] = "D:\python\python3.10.9\python.exe"

# 创建SparkConf类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")

# 基于SparkConf类对象创建SparkContext对象
sc = SparkContext(conf=conf)

# 准备一个RDD
# 通过paralLelize方法将Python对象加载到Spark内,成为RDD对象
rdd = sc.parallelize([1, 1, 3, 3, 5, 5, 7, 8, 8, 9, 10])

# 通过利用 distinct 方法将之前 RDD 对象中的数据进行去重处理,无需传参
rdd2 = rdd.distinct()

# 打印 如果要查看RDD里面有什么内容,需要用collect()方法
print(rdd2.collect())

# 停止SparkContext对象的运行(停止PySpark程序)
sc.stop()

运行结果如下,数据已经去重

在这里插入图片描述

4.7 sortBy方法

sortBy 算子

功能:对 RDD 数据进行排序基于你指定的排序依据

  • 接收一个处理函数,可用 lambda 快速编写
  • 函数表示用来决定排序的依据
  • 可以控制升序或降序
  • 全局排序需要设置分区数为 1

语法:

rdd.sortBy(func, ascending=False, numPartitions=1)
# func:(T) : 告知按照 rdd 中的哪个数据进行排序,比如 Lambda x: x[1] 表示按照rdd中的第二列元素进行排序
# ascending   True 升序    False 降序
# numPartitions: 用多少分区排序

演示代码:

# 1.构建执行环境入口对象
from pyspark import SparkConf, SparkContext
import os

os.environ["PYSPARK_PYTHON"] = "D:\python\python3.10.9\python.exe"
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")
sc = SparkContext(conf=conf)

# 2.读取数据文件
rdd = sc.textFile("wordcount.txt")

# 3.取出全部单词
word_rdd = rdd.flatMap(lambda a: a.split(" "))

# 4.将所有单词都转换成二元元组,单词为Key,value设置为1
word_with_one_rdd = word_rdd.map(lambda a: (a, 1))

# 5.对结果进行排序
result_rdd = word_with_one_rdd.reduceByKey(lambda a, b: a + b)
result_rdd.sortBy(lambda x: x[1], ascending=False, numPartitions=1)

# 6.打印输出结果
print(result_rdd.collect())

运行结果如下,根据每个单词出现的次数进行降序排序

在这里插入图片描述

4.8 练习案例2

JSON 商品统计需求案例

需求:使用 Spark 读取文件 order.txt 文件

  • 进行计算各个城市销售额排名,从大到小
  • 全部城市,有哪些商品类别在售卖
  • 北京市有哪些商品类别在售卖

order.txt 文件

在这里插入图片描述

演示代码:

# 1.构建执行环境入口对象
from pyspark import SparkConf, SparkContext
import os
import json

os.environ["PYSPARK_PYTHON"] = "D:\python\python3.10.9\python.exe"
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")
sc = SparkContext(conf=conf)

# TODO 需1: 城市销售额排名
# 1.1 读取文件得到RDD
file_rdd = sc.textFile("orders.txt")

# 1.2 取出一个个JSON字符串
json_str_rdd = file_rdd.flatMap(lambda x: x.split("|"))

# 1.3 将一个个JSON字符串转换为字典
dict_rdd = json_str_rdd.map(lambda x: json.loads(x))

# 1.4 取出城市和销售额数据
# (城市,销售额)
city_with_money_rdd = dict_rdd.map(lambda x: (x['areaName'], int(x['money'])))

# 1.5 按城市分组按销售额聚合
city_result_rdd = city_with_money_rdd.reduceByKey(lambda a, b: a + b)

# 1.6 按销售额聚合结果进行排序
result1_rdd = city_result_rdd.sortBy(lambda x: x[1], ascending=False, numPartitions=2)
print("需求 1 的结果是:", result1_rdd.collect())

# TODO 需求2: 全部城市有哪些商品类别在售卖
# 2.1 取出全部的商品类别
category_rdd = dict_rdd.map(lambda x: x['category'])

# 2.2 对全部商品类别进行去重
result2_rdd = category_rdd.distinct()
print("需求 2 的结果是:", result2_rdd.collect())

# TODO 需3: 北京市有哪些商品类别在售卖
# 3.1 过滤北京市的数据
beijing_rdd_data = dict_rdd.filter(lambda x:x['areaName'] == "北京")

# 3.2 取出全部商品类别
beijing_category_rdd = beijing_rdd_data.map(lambda x: x['category'])

# 3.3 进行商品类别去重
result3_rdd = beijing_category_rdd.distinct()
print("需求 3 的结果是:", result3_rdd.collect())

运行结果如下,

在这里插入图片描述

5. 数据输出

数据输出

数据输入:

  • sc.parallelize
  • sc.textFile

数据计算:

  • rdd.map
  • rdd.flatMap
  • rdd.reduceByKey

在这里插入图片描述

5.1 输出为 Python 对象

collect 算子

功能:将RDD各个分区内的数据统一收集到 Driver 中形成一个 List 对象

用法:

rdd.collect()

返回值是一个 list

reduce 算子

功能:对 RDD 数据集按照你传入的逻辑进行聚合

语法:

rdd.reduce(func)
# func: (T, T) -> T
# 2参数传入 1个返回值,返回值和参数要求类型一致

执行流程如下图:

在这里插入图片描述

代码:

rdd = sc.parallelize(range(110))
#将rdd的数据进行累加求和
print(rdd.reduce(lambda a, b: a + b))

返回值等同于计算函数的返回值

take 算子

功能:取RDD的前N个元素组合成list返回给你

用法:

sc.parallelize([3, 2, 1, 4, 5, 6]).take(5)[3,2,1,4,5]

count 算子

功能:计算 RDD 有多少条数据,返回值是一个数字

用法:

sc.paralelize([3, 2, 1, 4, 5, 6]).count()

小结:

Spark 的编程流程就是:

  • 将数据加载为 RDD(数据输入)
  • 对 RDD 进行计算(数据计算)
  • 将 RDD 转换为 Python 对象(数据输出)

数据输出的方法

  • collect:将 RDD 内容转换为 list
  • reduce:对 RDD 内容进行自定义聚合
  • take:取出 RDD 的前 N 个元素组成 list
  • count:统计 RDD 元素个数

数据输出可用的方法是很多的,本小节简单的介绍了4个

5.2 输出到文件中

saveAsTextFile 算子

功能:将 RDD 的数据写入文本文件中

支持本地写出,hdfs 等文件系统

代码:

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

rdd.saveAsTextFile(“…/data/output/test.txt”)

演示代码:

"""
演示将RDD输出到文件中
"""

from pyspark import SparkConf, SparkContext
import os

os.environ['PYSPARK_PYTHON'] = "D:/python/python3.10.9/python.exe"
os.environ['HADOOP_HOME'] = "D:/hadoop-3.0.0"
conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
sc = SparkContext(conf=conf)

# 准备RDD1
rdd1 = sc.parallelize([1, 2, 3, 4, 5])
# 准备RDD2
rdd2 = sc.parallelize([("Hello", 3), ("Spark", 5), ("Hi", 7)])
# 准备RDD3
rdd3 = sc.parallelize([[1, 3, 5], [6, 7, 9], [11, 13, 11]])

# 输出到文件中
rdd1.saveAsTextFile("output1")
rdd2.saveAsTextFile("output2")
rdd3.saveAsTextFile("output3")

注:当前所使用的该方法本质上依赖于大数据中的 hadoop 框架,直接使用会报错

在这里插入图片描述

因此,调用保存文件的算子,需要配置 Hadoop 依赖

  • 下载 Hadoop 安装包

    http://archive.apache.org/dist/hadoop/common/hadoop-3.0.0/hadoop-3.0.0.tar.gz

  • 解压到电脑任意位置

  • 在 Python 代码中使用 os 模块配置:os.environ[‘HADOOP HOMET’] = ‘HADOOP解压文件夹路径’

  • 下载 winutils.exe,并放入 Hadoop 解压文件夹的 bin 目录内

    https://raw.githubusercontent.com/steveloughran/winutils/master/hadoop-3.0.0/bin/winutils.exe

  • 下载 hadoop.dll,并放入 C:/Windows/System32 文件夹内

    https://raw.githubusercontent.com/steveloughran/winutils/master/hadoop-3.0.0/bin/hadoop.d

完成以上配置后,再次运行程序,没有报错,产生了三个文件夹 output1、output2、output3

在这里插入图片描述

打开任意一个文件夹,可以发现产生了很多文件,而产生这些文件的原因是因为当前的 RDD 有多个分区

在这里插入图片描述

由图中可以看出,产生了 16 和输出文件,说明此时的 RDD 有 16 个分区

saveAsTextFile 算子输出文件的个数是根据 RDD 的分区数量决定的,有多少分区就输出多少文件

本人的电脑 CPU 核心数为 16 核,因此默认设置为 16 个分区

数据([1, 2, 3, 4, 5])是被均匀分散到这 16 个分区中的,所以有的分区中有数据,有的分区没有数据,16 个文件中有 5 个文件有数据

没有数据的分区对我们而言是没有用的,但是只要有分区就会创建这个文件,怎样才能不生成多余的文件呢?

修改rdd分区为 1 个

方式1:SparkConf 对象设置属性全局并行度为 1

conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
conf.set("spark.default.parallelism", "1")
sc = SparkContext(conf=conf)

方式2:创建 RDD 的时候设置( parallelize 方法传入 numSlices 参数为 1)

rdd1 = sc.parallelize([12345],numSlices=1)
rdd1 = sc.parallelize([12345]1)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值