# Spark 学习项目(spark_project) 跟着 ChatGPT 课程的 Spark 学习笔记,用 **Scala + Java 双实现** 覆盖 Spark Core 的 RDD 基础、PairRDD、WordCount,并通过 MySQL 写入的示例表把练习串成一个迷你数仓案例。 > 课程三讲(一→三)一→一对应当前 `src/main/scala/org/exercises/exercises{1,2,3}` 三套练习;另有「线下课:RDD 创建/操作/重分区」的一份 Java 版 Demo。 ## 技术栈 | 类别 | 版本 | | ---------- | ------------------------------------------ | | JVM | Java 8 | | 语言 | Scala 2.11.12 + Java 8(双实现) | | 计算引擎 | Apache Spark 2.4.3(core + sql) | | 分布式 | Hadoop Client 2.7.3 | | 数据库 | MySQL 8.0.28 | | 连接池 | HikariCP 4.0.3 | | JDBC 工具 | commons-dbutils 1.6 | | 测试 | JUnit 3.8.1 | | 构建 | Maven 3 + scala-maven-plugin 4.8.1 + maven-assembly-plugin 3.7.1 | ## 项目结构 ``` spark_project/ ├── pom.xml # Maven 配置(强制 JDK 8 / Scala 2.11) ├── src/main/java/org/example/ │ ├── core/ │ │ ├── GroupByKeyDemo.java # Java 版 4 个核心 Demo │ │ ├── MyPartitioner.java │ │ ├── RddCreateDemo.java │ │ └── RepartitionVsCoalesce.java │ └── AppTest.java # JUnit 默认骨架 ├── src/main/scala/org/example/ │ ├── App.scala # Scala 入口:local[2] 模式 + word.txt WordCount │ ├── test.scala │ └── core/ # Scala 版同名 4 个 Demo │ ├── GroupByKeyDemo.scala │ ├── MyPartitioner.scala │ ├── RddCreateDemo.scala │ └── RepartitionVsCoalesce.scala ├── src/main/scala/org/exercises/ │ ├── exercises1/ # 第 1 课:Spark 入门 │ │ ├── demo/ # 演示 Demo1~5 │ │ └── exercises/Exercises1..5.scala # 课后 5 题(题目以中文注释形式嵌入文件头) │ ├── exercises2/ # 第 2 课:RDD 算子(map / filter / flatMap / reduce / foreach) │ └── exercises3/ # 第 3 课:PairRDD / reduceByKey / WordCount └── src/main/resources/ ├── create_table.sql # MySQL:Top10 平均评分电影 + 类别平均评分 ├── log4j.properties └── word.txt ``` ## 快速上手 ### 1. 准备环境 - **JDK 8**(`pom.xml` 已锁定 `maven.compiler.source/target=8`,高版本会编译失败) - **Maven 3.6+**(仓库根目录留有 `.mvn/`,但还没生成 `mvnw`,自行安装一个 `mvn` 到 `PATH` 即可) - 一台能跑 `local` / `local[2]` 模式的机器即可,**不需要真正的 Spark 集群** ### 2. 编译与打包 ```bash # 1) 拉依赖 mvn -DskipTests dependency:resolve # 2) 编译(Scala + Java 同时) mvn compile # 3) 跑测试(当前 src/test/ 仍为空,等价于空跑) mvn test # 4) 打 fat jar(含 Spark / Hadoop / MySQL 等所有依赖) mvn package # 5) 产出路径 ls target/spark_project-1.0-SNAPSHOT-jar-with-dependencies.jar ``` ### 3. 跑一个 Scala 入口 两种方式二选一: **方式 A:IDE 直跑**。在 IntelliJ IDEA 里直接打开 `pom.xml`,把以下任一对象作为 `main` 入口运行: - `org.example.App` — `local[2]` 模式读 `src/main/resources/word.txt`,做一次 `count + filter + flatMap → reduceByKey` 的 WordCount - `org.exercises.exercises3.exercises.Exercises5` — 纯数据集合版 WordCount(输出 `hello=3, spark=3, scala=1, is=1, powerful=1`) **方式 B:命令行跑 fat jar**。 ```bash java -cp target/spark_project-1.0-SNAPSHOT-jar-with-dependencies.jar \ org.example.App ``` > 默认 `pom.xml` 没配 `exec-maven-plugin`,所以 `mvn exec:java` 用不了,要么走方式 A,要么上 fat jar。 ## 三套练习索引 ### `exercises1` — 第 1 课:Spark 是什么,以及第一个 Spark 程序 源:`src/main/scala/org/exercises/exercises1/` 主题:`SparkConf` / `SparkContext` 创建、并行化集合、读取外部文件。 代表题: | 编号 | 题目要点 | | ----- | ------------------------------------------------- | | Ex 1 | 搭一个 `SparkContext`,`setMaster("local")` | | Ex 2 | 从本地/集合源构造 RDD | | Ex 3 | 基础转换算子 | | Ex 4 | 触发动作算子 | | Ex 5 | 综合:第一个本地 WordCount | ### `exercises2` — 第 2 课:RDD 常用算子 源:`src/main/scala/org/exercises/exercises2/` 主题:单值 RDD 的转换与动作。 | 编号 | 算子 | | ----- | ------------ | | Ex 1 | `map` | | Ex 2 | `filter` | | Ex 3 | `flatMap` | | Ex 4 | `reduce` | | Ex 5 | `foreach` | ### `exercises3` — 第 3 课:PairRDD 与 reduceByKey 源:`src/main/scala/org/exercises/exercises3/` 主题:键值对 RDD 常用算子与正式 WordCount。 | 编号 | 算子 / 内容 | | ----- | -------------------------------------------------------- | | Ex 5 | 正式练 WordCount:`flatMap → map → reduceByKey → collect` | > `exercises1/2/3/demo/` 目录下还有 5 个对应演示,可在写练习前打开当作参考实现。 ## MySQL 结果表 `src/main/resources/create_table.sql` 里两张表是后续评分分析的目标输出: | 表名 | 主用途 | | -------------------------- | ---------------------------------- | | `top_ten_avg_ratings` | TopN 平均评分电影(`movie_id` 唯一) | | `genres_average_rating` | 类型平均评分(`genres` 唯一) | 依赖侧(`pom.xml`)已经预备好: - `mysql-connector-java` 8.0.28 - `HikariCP` 4.0.3 - `commons-dbutils` 1.6 下一步只要写真实的 Spark SQL / DataFrame → JDBC 写入逻辑即可。使用前请在 MySQL 里先执行 `create_table.sql`。 ## 提交规范 仓库已有 6 条 commit,主题风格统一为**简体中文 + 简短摘要**: ``` feat:ChatGPT 第 1 课:Spark 是什么,以及第一个 Spark 程序 feat:ChatGPT 第 2 课:RDD 常用算子 feat:ChatGPT 第 3 课:PairRDD 与 reduceByKey 线下课:RDD的创建、RDD的操作、RDD重分区 feat:首次提交 ``` 继续沿用 `feat:<主题>` 形式,**中文一句话主题**,变更保持原子(新题 / 新课一个 commit)。默认分支 `main`,从 `main` 拉 feature 分支再合,禁止直接 push。 ## 安全约定 - `target/`、`.idea/`、`*.iml` 等构建/IDE 产物已在 `.gitignore` - **MySQL / Hadoop 凭据**一律外部化(环境变量或 `*.local.properties`,并加入 `.gitignore`),不要写进 `src/main/resources/` - 不要把含个人 token 的 fat jar 提交到仓库 ## 下一步 - [ ] `src/test/` 仍为空,按练习补 JUnit 3 测试用例 - [ ] 把 Spark SQL/DataFrame 的分析结果真正写回 `top_ten_avg_ratings`、`genres_average_rating` - [ ] 加一份 `.mvn/wrapper/maven-wrapper.properties` 让团队对齐 Maven 版本