学习笔记

  1. Key-Value RDD操作(重点突破)
    常用Pair RDD转换操作:
    scala
    // 准备数据
    val rdd = sc.parallelize(Seq(
    ("apple", 3), ("banana", 2), ("apple", 5),
    ("orange", 1), ("banana", 4)
    ))

// 1. reduceByKey - 相同key聚合(宽依赖)
val sumByKey = rdd.reduceByKey((x, y) => x + y)
// 结果: (apple,8), (banana,6), (orange,1)

// 2. groupByKey - 分组为迭代器(性能较差)
val grouped = rdd.groupByKey()
grouped.mapValues(_.sum) // 等同于reduceByKey但效率低

// 3. mapValues/flatMapValues - 只操作value
val doubleValues = rdd.mapValues(_ * 2)
// 结果: (apple,6), (banana,4), (apple,10), (orange,2), (banana,8)

// 4. keys/values - 提取键或值
rdd.keys.collect() // 所有key
rdd.values.collect() // 所有value

// 5. sortByKey - 按键排序
val sorted = rdd.sortByKey() // 升序
val descSorted = rdd.sortByKey(false) // 降序

// 6. join操作 - 表连接
val rdd1 = sc.parallelize(Seq(("a", 1), ("b", 2), ("c", 3)))
val rdd2 = sc.parallelize(Seq(("a", "x"), ("b", "y")))
val joined = rdd1.join(rdd2) // 内连接
// 结果: (a,(1,x)), (b,(2,y))
关键概念:宽依赖 vs 窄依赖
scala
// 窄依赖 - 每个父分区最多被子分区使用一次
val mapRDD = rdd.map(x => (x._1, x.2 * 2)) // 一对一
val filterRDD = rdd.filter(
._2 > 2) // 一对一

// 宽依赖 - 需要shuffle,父分区被多个子分区使用
val reduceRDD = rdd.reduceByKey(_ + ) // 需要shuffle
val groupRDD = rdd.groupByKey() // 需要shuffle
2. RDD持久化(Persistence)
scala
// 1. 基本持久化操作
val rdd = sc.textFile("data/largefile.txt")
.flatMap(
.split(" "))
.map((_, 1))

// 第一次使用会计算并缓存
rdd.persist(StorageLevel.MEMORY_ONLY) // 内存缓存
// 或
rdd.cache() // 等同于persist(MEMORY_ONLY)

// 多次使用同一RDD
val count1 = rdd.count() // 第一次触发计算,缓存
val count2 = rdd.groupByKey().count() // 复用缓存数据

// 2. 不同存储级别对比
val level1 = StorageLevel.MEMORY_ONLY // 仅内存(默认)
val level2 = StorageLevel.MEMORY_AND_DISK // 内存溢出则磁盘
val level3 = StorageLevel.MEMORY_ONLY_SER // 内存序列化(节省空间)
val level4 = StorageLevel.DISK_ONLY // 仅磁盘

// 3. 手动清理缓存
rdd.unpersist() // 移除缓存

// 4. 检查点(Checkpoint)- 切断血缘
sc.setCheckpointDir("hdfs://checkpoint-dir")
rdd.checkpoint() // 保存到可靠存储,切断依赖链
持久化策略选择指南:
MEMORY_ONLY:小数据集,内存充足

MEMORY_AND_DISK:大数据集,避免重复计算

MEMORY_ONLY_SER:内存紧张,但需要CPU序列化

DISK_ONLY:数据太大,但计算代价高

  1. Spark UI监控与分析
    访问Spark UI
    bash

Local模式:默认 http://localhost:4040

多个应用顺序端口:4040, 4041, 4042...

监控关键指标:
scala
// 实战:编写一个稍复杂的作业来观察UI
object SparkMonitorDemo {
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder()
.appName("Spark Monitoring Demo")
.master("local[*]")
.getOrCreate()

val sc = spark.sparkContext

// 1. 读取数据
val rdd = sc.textFile("data/sales.csv")
  .mapPartitionsWithIndex((idx, iter) => {
    println(s"Partition $idx processing")
    iter.map(_.split(","))
  })

// 2. 多次使用的RDD - 缓存优化
val parsedRDD = rdd.map(arr => (arr(0), arr(1).toDouble))
parsedRDD.cache()

// 3. 计算统计信息
val totalSales = parsedRDD.map(_._2).sum()
val avgSales = totalSales / parsedRDD.count()

// 4. 分组聚合(产生shuffle)
val categorySales = parsedRDD.reduceByKey(_ + _)
val topCategories = categorySales.sortBy(_._2, false).take(10)

// 5. 等待用户查看UI
println("Check UI at http://localhost:4040")
Thread.sleep(60000)  // 暂停1分钟供查看UI

spark.stop()

}
}

posted @ 2026-03-08 12:46  Lomook  阅读(3)  评论(0)    收藏  举报