Spark:DF创建临时表createTempView结合cache/persist缓存优化执行效率

459 阅读1分钟

环境 spark 2.4.6

代码逻辑

  1. 从ip库读出text文件类型的库文件。
  2. 提取ip库文件中的需要字段,并转为DF1。
  3. 从HDFS中读取被解析文件(包含ip字段,文件为parquet格式),转为DF2。
  4. 将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 格式 image.png

  • 未对df执行cache缓存的执行效果:

image.png

image.png

  • 对df执行cache缓存后的执行效果:

image.png

image.png

结论

可以看出:当对df执行缓存之后,会明显减少下游重新计算df的计算时间,但势必会增加cache执行时的资源消耗。如果df的计算代价大于缓存代价,那么该df就值得被缓存,否则就需要进一步考虑该df是否值得被缓存。