想使用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()
用户平均分
df = spark.read.format("csv").option(encoding="utf-8").schema(schema).load("c:\\")
df.groupby("age").avg("rank").withColumns("avg("rank")",avg_rank)
分区数=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()
RDD的执行流程: RDD->DAGScheduler->TaskScheduler->Worker
sparksql: SELECT /*+ broadcast(a_b) */ * FROM (SELECT /*+ broadcast(a) */ * FROM a JOIN b ON ...) AS a_b JOIN c ON ...
原理: 将小表广播到每个执行器后,构建hash table, 关联有无通过大表关联字段作为key, 从hash表映射即可判断是否有匹配。 相当于遍历一次大表分区即可, 而且分布式运行,性能较好。
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 将会基于统计信息自动地为每一列选择一种压缩编码方式