SparkSQL

f3af62d0636a44c6abf82f0206734231.png

    想使用Dbeaver工具连接spark使用sparkSql访问Hive表,就要用到一个东西SparkThirdService;这东西就类似java jdbc连接,连接hive的hiveService2这种东西;

#进入Spark安装目录
sudo -u hive ./sbin/start-thriftserver.sh \
--hiveconf hive.server2.thrift.port=10016 \
--hiveconf hive.server2.thrift.bind.host=19x.xxx.xxx.xx \
--hiveconf spark.sql.warehouse.dir=hdfs://xxxx.com:8020/warehouse/tablespace/managed/hive \
--master yarn \
--executor-memory 4G \
--conf spark.sql.shuffle.partitions=10

DF

有行有列

DF = spark.createDataFrame(rdd,schema["name","age"])#表的描述信息

DF.printSchema()
DF.show(20,false)#展示数据数,是否对列进行截断

DF.createOrReplaceTempView("People")

表结构是由 structType类对象构建而成

from pyspark.sql.types import StructType,StringType,IntegerType

rdd = sc.textFile().map()

schema = StructType().add("name",StringType,nullable=False).\
             add("age",IntegerType,nullable=False)

createDataFrame(rdd,schema)

#法一
rdd.toDF("")
#法2
rdd.toDF(schema)

import pandas as pd

pdf = pd.DataFrame({"id":[1,2,3]})

df=spark.createDataFrame(pdf)
df.printSchema()
df.show()

#读取text,读取了某个格式表结构为某某且路径在某某的文件转换成DF
spark.read.format().schema().load()

#标准API读取json,json自带schema
spark.read().format().load()

##可以指定很多属性
spark.option()

#parquet内置schema,且以列为存储格式,序列化存储在文件中
spark.read().format("parquet").load("")


#SparkSql操作风格

#DSL
df.select().show()

#col object
name_col = df["name"]
df.select(nam_col).show()

df.filter("score <99").show()


#分组聚合
df.groupby("subject").count().show()
#注意groupby的返回值 Groupedata 不是DF 是有分组关系的数据结构


#全局表,可以跨越多个SparkSession使用 临时表只能在一个SS中使用
createGlobalTempView()



fa341b4a804c49c4a2e07c093b61f083.png

用户平均分

df = spark.read.format("csv").option(encoding="utf-8").schema(schema).load("c:\\")

df.groupby("age").avg("rank").withColumns("avg("rank")",avg_rank)

aefed524f0fc4392b0ed3320a8679b46.png

分区数=tasks数,与设置并行度的参数互相独立 parallelism

数据去重API:

df.dropDuplicates(['指定需要去重的列']).show()

缺失值处理:

df.dropna(thresh==2,subset=[]) 删除存在空值的行,最少满足2个有效列,subset限定列的范围

df.fillna("指定内容的填充")

import pyspark.sql.functions as F df2 = df.select([ F.concat_ws(",", c).alias(c)

写出

df.write.mode("overwrite").format().save()

5f435a20e9b04bfd89f2cb90b92560a0.png

RDD的执行流程: RDD->DAGScheduler->TaskScheduler->Worker

32213a2a07b9437c80ce8c14e8c452b6.png

 84f80be927e34cc689f975ce332485a9.png

5ea9ba9b1d94477a8f0b17a69eb103d4.png

sparksql:      SELECT /*+ broadcast(a_b) */ * FROM (SELECT /*+ broadcast(a) */ * FROM a JOIN b ON ...) AS a_b JOIN c ON ...
原理: 将小表广播到每个执行器后,构建hash table,    关联有无通过大表关联字段作为key, 从hash表映射即可判断是否有匹配。  相当于遍历一次大表分区即可, 而且分布式运行,性能较好。

8c86ac372863433e9d27474f45924e41.png

sparkSql优化:

计算:

1.设置Shuffle的并行度 spark.setConf("spark.sql.shuffle.partitions",4)

还有其它资源参数

2.明确列名

3.并行处理,使用foreach算子

5.spark.sql.autoBroadcastJoinTreshold,默认10MB,设置较小的值可以让spark在join的时候将小表广播分发到各个节点。注:大小 <= 设置值 的表,都会被广播出去。结合广播变量去说。

6.join

spark支持所有类型的join:

  • inner join
  • left outer join
  • right outer join
  • full outer join
  • left semi join
  • left anti join 

spark中join的基本实现流程是将参与join的两张表抽象为流式遍历表(streamIter)和查找表(buildIter)

在实际计算时,spark会基于streamIter来遍历,每次取出streamIter中的一条记录rowA,根据Join条件计算keyA,然后根据该keyA去buildIter中查找所有满足Join条件(keyB==keyA)的记录rowBs,并将rowBs中每条记录分别与rowAjoin得到join后的记录,最后根据过滤条件得到最终join的记录。

从上述计算过程中不难发现,对于每条来自streamIter的记录,都要去buildIter中查找匹配的记录,所以buildIter一定要是查找性能较优的数据结构。spark提供了三种join实现:sort merge join、broadcast join以及hash join。
 

Hash join实现

spark提供了hash join实现方式,在shuffle read阶段不对记录排序,反正来自两格表的具有相同key的记录会在同一个分区,只是在分区内不排序,将来自buildIter的记录放到hash表中,以便查找,如下图所示。

由于Spark是一个分布式的计算引擎,可以通过分区的形式将大批量的数据划分成n份较小的数据集进行并行计算。这种思想应用到Join上便是Shuffle Hash Join了。利用key相同必然分区相同的这个原理,SparkSQL将较大表的join分而治之,先将表划分成n个分区,在对buildlter查找表和streamlter表进行Hash Join。
 

  • buildIter总体估计大小超过spark.sql.autoBroadcastJoinThreshold设定的值,即不满足broadcast join条件
  • 开启尝试使用hash join的开关,spark.sql.join.preferSortMergeJoin=false
  • 每个分区的平均大小不超过spark.sql.autoBroadcastJoinThreshold设定的值,即shuffle read阶段每个分区来自buildIter的记录要能放到内存中
  • streamIter的大小是buildIter三倍以上

Sort Merge Join 实现

上面介绍的实现对于一定大小的表比较适用,但当两个表都非常大时,显然无论适用哪种都会对计算内存造成很大压力。这是因为join时两者采取的都是hash join,是将一侧的数据完全加载到内存中,使用hash code取join keys值相等的记录进行连接。

要让两条记录能join到一起,首先需要将具有相同key的记录在同一个分区,所以通常来说,需要做一次shuffle,map阶段根据join条件确定每条记录的key,基于该key做shuffle write,将可能join到一起的记录分到同一个分区中,这样在shuffle read阶段就可以将两个表中具有相同key的记录拉到同一个分区处理。前面我们也提到,对于buildIter一定要是查找性能较优的数据结构,通常我们能想到hash表,但是对于一张较大的表来说,不可能将所有记录全部放到hash表中,SparkSQL采用了一种全新的方案来对表进行Join,即Sort Merge Join。这种实现方式不用将一侧数据全部加载后再进行hash join,但需要在join前将数据排序,如下图所示:

Broadcast Join实现

为了能具有相同key的记录分到同一个分区,我们通常是做shuffle,而shuffle在Spark中是比较耗时的操作,我们应该尽可能的设计Spark应用使其避免大量的shuffle。。那么如果buildIter是一个非常小的表,那么其实就没有必要大动干戈做shuffle了,直接将buildIter广播到每个计算节点,然后将buildIter放到hash表中,如下图所示。

 

 

spark内部有很多地方都使用的广播变量功能,比如spark sql的join有一种broadcast join,就是使用广播变量实现的小表join的优化; 

 

 

存储:

4.经常使用的表进行 缓存,spark.cacheTable(tableName) 使得spark使用内存列存储格式 进行缓存,并进行列值裁减,来最小化内存和GC消耗。

sql写法:cache table tableName

另一种是持久化

6.数据分区和分桶、压缩

7.合适的存储格式: parquet,支持谓词下推,列式存储并裁剪

8.spark.sql.inMemoryColumnarStorage.compressed

默认为:true
Spark SQL 将会基于统计信息自动地为每一列选择一种压缩编码方式

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值