Spark 复习(期末考试总结)

Spark

优秀博客链接:

https://blog.csdn.net/weixin_42263032/article/details/107191349

RDD

💛Spark RDD APPlication开发步骤:

1 通过findspark找到并引用pyspark

2 创建sparkContext对象

3 读取数据源,生成RDD对象

4 对RDD进行transframtion操作

5 对RDD进行actoin操作

import findspark
findspark.init()
from pyspark import SparkContext

sc = SparkContext()
read_RDD = sc.textFile(r'filePath')

🚗Action算子
  • count() : 返回RDD的行数
  • first() : 返回RDD中第一行数据
  • take(n) : 以列表(list)形式返回前n行数据
  • collect() : 以列表(list)形式返回RDD中所有行的数据
🚙 Transformation算子
  • map(): 一一映射
# 示例: 将所有单词改为小写后返回
wordsRDD.map(lambda x : x.lower()).collect()

# 示例2:将sentencesRDD每一行单词的首字母都改为大写,并返回
sentencesRDD.map(lambda x : x.title()).collect()
  • flatMap():一对多映射
# 示例:用各个单词的小写形式及长度构成元祖,并返回
sentencesRDD.flatMap(lambda x: [(i.lower(),len(i)) for i in x.split(' ')]).collect()
  • filter():过滤
# 示例:去掉表头
firstLine = salesRDD.first()
noHeaderRDD = salesRDD.filter(lambda x : x != firstLine)

注释:获取字符串中以“2022”开头的

lambda x:x.startswith('2022')
  • 并集-》

  • union():不去重

  • distinct() :去重

  • 交集-》

  • intersection: 自动去重

  • 差集-》

  • subtract: 不去重

  • reduceByKey()

    rdd.map(lambda x:(x.split(' '),1)).reduceByKey(lambda x,y :x+y).clooect()
    
  • groupyKey()

  • mapValues()

#两个在一起用
from statistics import mean
rdd.map(lambda x:(x['sex'],x['score'])).groupByKey().mapValues(mean).collect()
✈️Pair RDD Transformation算子
  • sortByKey()
rdd.sortByKey(keyfunc = lambda x : x.lower(),ascending=False).collect()
**(keyfunc = fn,ascending=False/True)
  • join()
x = sc.parallelize([("a", 1), ("b", 4)])
y = sc.parallelize([("a", 2), ("a", 3)])
x.join(y).collect()

#获得结果:
[('a', (1, 2)), ('a', (1, 3))]
  • leftOuterJoin
  • rightOuterJoin
🛰Pair RDD Action算子
  • collectAsMap()

    rdd = sc.parallelize([(1, 2), (3, 4),(1,4)])     # key相同时,后面key对应的value会覆盖前面的value
    rdd.collectAsMap()
    # 结果
    {1: 4, 3: 4}
    
  • countByKey()

rdd.countByKey()
有两个方法,分别是 keys(),values(),可以取到对应的列表
使用 items(),可以得到(键,值)元组列表
🥇分区

默认分区个数与cpu逻辑处理服务器个数一直

查看分区:

  • getNumPartitions()

查看分区上的数据:

  • glom().collect()
如何控制分区数量?

🅰️实例化SparkContext时指定参数:

sc = SparkContext("local[2]")
# 默认改变全局配置,
# 可以使用 sc.parallelize(text,4) 指定4个分区,可以有效,但是全局不变

🅱️读取数据时:

⚔️parallelize()

list01RDD = sc.parallelize(list01, 4)      # 4表示生成4个分区
list01RDD.getNumPartitions()  

🗡textFie(‘path’,min_num):

通过textFile()只能指定最小分区数,无法指定具体的分区数量

◀️专门的分区Transformation算子

  • repartitioin(n):可以增加或减少(减少时建议使用 coalesce()方法)

  • coalesce(n):减少分区至n个

  • partitionBy():针对Pair RDD。将Key相同的放到同一个分区

pairRDDRe = pairRDD.partitionBy(2, lambda x : x == 'b' )     # 将key等于'b'的放在一个分区
pairRDDRe.glom().collect()
# 结果:[[('a', 1), ('c', 1), ('a', 3), ('c', 2)], [('b', 2), ('b', 4)]]
  • repartitionAndSortWithPartitions(n):针对Pair RDD。根据针对Key的规则对数据进行分区,并根据Key排序
pairRDD = sc.parallelize([(1, "a"), (5, "b"), (6, "c"), (4, "e"), (2, "f"), (9, "g"), (11, "w"), (19, "x"), (15, "z")])
pairRDDRe = pairRDD.repartitionAndSortWithinPartitions(3, lambda x : x % 3, False)
pairRDDRe.glom().collect()
# 根据'3的余数'分区,分区内key降序
为啥要使用分区?

(1)数据量大时,尽量增加分区

(2)数据量小时,不要增加分区,避免cpu和内存的空分配和回收

(3)优化后续的groupBy 等过程(例如:partitionBy())

(4)决定保存的文件的数量

Shuffle

啥是Shuffle?

进行实际的Transformation操作时,一个分区中的数据被移动到多个分区中

哪些Transformation不需要Shuffle?

map,filter, flatmap, mapValues都不需要shuffle。这意味着各个partition可以并行执行(各自执行各自的操作,谁也不用等谁)。
这类Transformation被称为Narrow Transformation(窄依赖

有哪些Transformation也需要Shuffle

Shuffle意味着无法再并行执行,需要等待所有partition都执行完毕,才能继续往下进行
这类Transformation被称为Wide Transformation(宽依赖

reduceByKey、union、coalesce

持久化

  • persist()
1).为什么要使用持久化?

每次进行Action操作,都是重新开始,即从读取数据开始,效率低下。因此,当需要对一个RDD进行多次Action操作之前,应该先进行持久化 。

2). 持久化的级别有哪些? 课本P54

StorageLevel(useDisk, useMemory, useOffHeap, deserialized, replication=1)

总而言之:可以缓存到JVM内存中、非JVM内存中、磁盘上

3). 使用建议:

尽可能使用MEMORY_ONLY。 如果内存不够大,再尝试使用MEMORY_ONLY_SER,最后考虑磁盘

  • Cache():仅仅能缓存到内存中,因此rdd.cache() 等价于 rdd.persist(MEMORY_ONLY)

  • 检查点

持久化操作仍存在丢失的风险,所以可以使用checkpoint,设置一个还原点(相当于持久化磁盘)

也可以在Shuffle之后设置,从而避免还原丢失的RDD再次进行Shuffle操作

查看血统
distinctRdd = rdd.distinct()
distinctRdd.toDebugString().decode().split('\n')            # 设置检查点之前,血统是这样的
设置检查点
sc.setCheckPointDir('filePath') # 设置checkpoint目录
distinctRdd.cache()  # 缓存rdd,避免下句调用checkpoint时,重新计算rdd
distinctRdd.checkpoint()  #设置检查点

结论:设置检查点后,就可以从检查点开始恢复某些丢失的rdd了,因此就不需要之前的血统了。即,设置检查点后将删除其对父RDD的引用。

DataFrame

DataFrame编程步骤:

step 1: 引入相关模块

step 2: 导入并创建SparkSession对象

step 3: 通过SparkSession对象读取数据源,生成DataFrame对象

step 4: 对DataFrame进行Transformation操作(有两种方式)

方式(1) 通过DataFrame API 提供的方法

方式(2) 通过Spark SQL

step 5: 对DataFrame进行Action操作

import findspark
findspark.init()
from pyspark.sql import SparkSession
spark = SparkSession.builder.getOrCreate()  
Df = spark.createDataFrame(data,['id','name','score','province'],header = False,inferSchema=True)

🖤注: 在创建SparkSession对象时,也已经创建了SparkContext对象,因此,需要从SparkSession对象中获得SparkContext对象

想要使用,可以这样获得

sc = spark.sparkContext
🌩Action 操作
  • show()
  • head()
  • tail()
  • take()
  • collect()
  • count()
  • write.csv(‘csv_path’,sep=‘#’) :保存为 csv 文件
  • write.text(‘fileName’)
# text为非结构化数据,先把列合并
from pyspark.sql.functions import concat_ws
df_1_new = df_1.select(concat_ws(",", df_1.student_name, df_1.subject_name, df_1.subject_score).alias("new_col"))  #合并所有列

df_1_new.coalesce(1).write.text("txt_result01")
  • **printSchema()**输出表结构

  • **colums()**输出列名

  • 创建 Dataframe

    通过***toDF()***方法将RDD转变到DataFrame

    通过 createDataFrame 方法

    通过 spark.read.json 或 spark.read.csv

    从 关系型数据库创建(mysql):

    spark = SparkSession \
        .builder \
        .config("spark.driver.extraClassPath", "mysql-connector-java-8.0.28.jar") \
        .getOrCreate()
    
    dataframe_mysql = spark.read\
        .format("jdbc") \
        .option("url", "jdbc:mysql://localhost/chapter01") \
        .option("driver", "com.mysql.jdbc.Driver") \
        .option("dbtable", "student").option("user", "root") \
        .option("password", "root").load()
    
    ## 需要根据自己情况对如下配置进行修改:
    ## dftest: 数据库名称
    ## users: 数据库表名
    ## root: 用户名
    ## sa123456.: 密码
    
    dataframe_mysql.show()                                      ### pd.read_sql(), pd.read_sql_table(), pd.read_sql_query()
    
⬛️Transformation操作
列操作
1、选择某些列
  • select()
  • drop()
四种写法等价
dfSelect = df.select("co1","co2")
dfSelect = df.select(['co1','co2'])
from pysprk.sql.functoins import col
dfSelect = df.select(col("co1"),col("co2"))
dfSelect = df.select(df["co1"],df["co2"])

#选择所有列
df.select('*')
  • 通过spark SQL
df.createOrReplaceTempView('view_name')
dfSql = spark.sql("select co1,co2 from view_name")
2、重命名
  • withColumnRenamed
dfRenamed = dfCsvFile.withColumnRenamed('rep', 'new name').withColumnRenamed('region', 'newName area')
  • selectExpr
dfCsvFile_selectCols = dfCsvFile.selectExpr("rep name", "region area")
  • Spark SQL
dfCsvFile.createOrReplaceTempView('dfCsvFile_view')
spark.sql("SELECT rep AS name, region area FROM dfCsvFile_view").show()   
3、添加新列
from pyspark.sql.functions import year, round, format_number
dfSelected05 = dfCsvFile.select("region", "item", round(dfCsvFile.Units * dfCsvFile.UnitCost, 2).alias('Totals'))
dfSelected01 = dfCsvFile.withColumn('Day of Year', year('OrderDate'))          ### df['新列名'] = [], df.assign()
dfSelected02 = dfCsvFile.withColumn('discount', col('UnitCost') * 0.9)

4、更改列类型
from pyspark.sql.types import DateType
dfCasted = dfCsvFile.withColumn('OrderDate', dfCsvFile['OrderDate'].cast(DateType()))
dfCsvFile02 = dfCsvFile.selectExpr("cast(OrderDate as date)", "cast (Units as double)")
dfCsvFile.createOrReplaceTempView("dfCsvFile_view")
dfModifyType = spark.sql("SELECT CAST(OrderDate as date), CAST (Units as double)  FROM dfCsvFile_view")
5、根据某些列排序
orderedDF02 = dfCsvFile.orderBy('OrderDate', ascending = False)
6、分组
from pyspark.sql.functions import round, mean, sum, col
dfCsvFile.groupBy('Region').count().show()
dfCsvFile.groupBy('Region').sum().show()
dfSelected.groupBy('Year').sum('Total').show()                             
dfSelected.groupBy('Year').agg(round(sum("Total"),2).alias("Total")).show()
行操作
1、过滤行
  • filter()
  • where()
dfCsvFile.filter((dfCsvFile['UnitCost'] > 5) & (dfCsvFile['UnitCost'] < 10)).show()
dfCsvFile.where((dfCsvFile['UnitCost'] > 5) & (dfCsvFile['UnitCost'] < 10)).show(
2、去重
  • distinct()
  • countDistinct()
3、统计
from pyspark.sql.functions import mean, max, min
dfCsvFile.select(round(mean('UnitCost'), 2)).show()                ### df.mean(), df.max(), df.sum(), df.count()等
dfCsvFile.select(max('UnitCost'), min('UnitCost')).show()
缺失值
  • dropna()
df.dropna(submit=['co1','co2'])
  • fillna()
dfMissing.fillna(0)
两个DataFrame 之见的操作
  • union():相当于堆叠
  • join()
  • left_outer()
  • right_outer()

Spark Streaming

Spark Streaming编程步骤

step1:引入相关模块,创建SparkContext对象

step2:导入并实例化 StreamingContext(sc,time)

step3:读取流数据

方式一:以RDD读取

方式二:以DataFrame 形式

step4:进行transformation 操作

step5:进行输出操作

step6:start()

step7:控制处理时间

if ssc.awaitTerminationOrTimeOut(30) ==False

step8: stop()

import findspark
findspark.init()
from pyspark import SparkContext
sc = SparkContext()
from pyspark.streaming import StreamingContext
ssc = StreamingContext(sc,5)

inputStream = ssc.queueStream([rdd1,rdd2,rdd3])
操作
  • updateStateByKey( fuc*)

针对 PairDStream,By Key操作

  • window(size,splide): 设置滑动窗口
pairDStream.window(15,10).saveAsTextFiles('./window/output')
  • countByWindow(size,splide): 得到窗口中块个数

  • countByValueAndWindow(size,splide):

inputDStream.countByValueAndWindow(15, 5).pprint()
  • reduceByKeyAndWindow(lambda , ,size,splide)
inputDStream.reduceByKeyAndWindow(lambda x,y: x if x > y else y ,None, 15, 5).pprint()
  • textFileStream()流文件

文件修改日期必须晚于start()执行日期

textFileDStream = ssc.textFileStream('StreamingData01')
reduceDStream = textFileDStream.filter(lambda x : 'is' in x) 
reduceDStream.pprint()

Graph

一、图的重要概念

图是由顶点的非空有限集和边的有限集构成,记作G=<V,E>

(1) 顶点、边
(2) 无向图、有向图
(3) 度、入度、出度

度 有向图和无向图都有;
入度和出度只有有向图存在

(4) 连通图、强连通图

连通图 针对无向图;

强连通图 针对有向图;

极大连通子图指 再加上一个点就不连通了的子图;

(5) 连通分量、强连通分量

无向图G的极大连通子图称为G的连通分量,可以存在多个;

强连通分量 针对有向图而言;

(6) 简单图、多重图、伪图

多重图指存在平行的边;
伪图指图存在自环;

二、Spark GraphFrame的编程步骤

step1、引入相关模块

step2、创建SparkSession对象

step3、创建 Vertices Frame和Edge Frame,表示图中的节点和边

step4、创建GraphFrame对象,表示图数据结构

step5、transformatoin 和 action 操作

import findspark
findspark.init()
from pyspark.sql import SparkSession
spark = SparkSession.builder \
                    .config('spark.jars.packages', 'graphframes:graphframes:0.8.2-spark3.0-s_2.12') \
                    .getOrCreate()
                    
# 创建顶点DataFrame实例
data_V = [('a', 'Alice', 34), ('b', 'Bob', 36), ('c', 'Charlie', 30), ('d', 'David', 29), ('e', 'Esther', 32), ('f', 'Fanny', 36), ('g', 'Gabby', 60)]
cols_V = ['id', 'name', 'age']
vertices = spark.createDataFrame(data_V, cols_V)

# 创建边DataFrame实例
data_E = [('a', 'b', 'friend'), ('b', 'c', 'follow'), ('c', 'b', 'follow'), ('f', 'c', 'follow'), ('e', 'f', 'follow'), ('e', 'd', 'friend'), 
         ('d', 'a', 'friend'), ('a', 'e', 'friend')]
cols_E = ['src', 'dst', 'relationship']
edges = spark.createDataFrame(data_E, cols_E)

# 创建图对象
from graphframes import GraphFrame		 	
graph = GraphFrame(vertices, edges)

三、创建图实例

(1) 创建顶点DataFrame对象:必须有id列,作为顶点的唯一标识

(2) 创建边DataFrame对象:必须有src和dst列

(3) 根据顶点和边DataFrame实例,创建图实例

  • 1
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值