环境 spark 2.4.6
代码逻辑
- 从ip库读出text文件类型的库文件。
- 提取ip库文件中的需要字段,并转为DF1。
- 从HDFS中读取被解析文件(包含ip字段,文件为parquet格式),转为DF2。
- 将DF1与DF2通过ip字段进行join,实现ip字段解析,将结果转为DF3,最后输出到HDFS。
// 伪代码
// 读ip文件,转DF
val lines_ipResource = sc.textFile(ipResourcePath)
val ipInfoRow = lines_ipResource.map(x => {
......
Row(ip, province, city, isp)
})
val ipInfoDf = spark.createDataFrame(ipInfoRow, getIpInfoSchema())
// ipInfoDf.cache() // 缓存优化
ipInfoDf.createTempView("ipInfo")
// 读被解析文件,并转DF
val odsAccessDf= spark.read.parquet(inputPath).coalesce(MakeInputCoalesce(x, y, z)
val odsAccessExtendRow: RDD[Row] = odsAccessDf.rdd.mapPartitions(
partition => {
val rows: Iterator[Row] = partition.map(record => {
......
})
rows
})
val preDwdAccessDf = spark.createDataFrame(odsAccessExtendRow, getOdsAccessExtendSchema())
//preDwdAccessDf.cache() //缓存优化
preDwdAccessDf.createTempView("preDwdAccess")
val rows = preDwdAccessDf.count()
// join
val dwdAccessDf: DataFrame = spark.sql(
"""
|
|select
|... ... ...
|from preDwdAccess a
|left join ipInfo i
|on a.ip = i.ip
|""".stripMargin).coalesce(MakeOutputCoalesce(x, y, z))
// 数据写出
dwdAccessDf.write.mode(SaveMode.Overwrite)
.format("parquet")
.save(outputPath)
-
输入数据大小 parquet 格式
-
未对df执行cache缓存的执行效果:
- 对df执行cache缓存后的执行效果:
结论
可以看出:当对df执行缓存之后,会明显减少下游重新计算df的计算时间,但势必会增加cache执行时的资源消耗。如果df的计算代价大于缓存代价,那么该df就值得被缓存,否则就需要进一步考虑该df是否值得被缓存。