180 lines
7.5 KiB
Markdown
180 lines
7.5 KiB
Markdown
# 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 版本
|