说明
本文依赖于上一篇文章:【spark学习】 spring boot 整合 spark 的相关内容,请先阅读上一篇文章,将spark需要的环境先配置好,并测试通过之后再进行此文章的阅读和操作。
RDD学习
RDD介绍
想象一下你有一个大大的数据表,里面包含了很多很多的信息。如果你想对这些数据进行操作,比如筛选出符合条件的数据、或者对数据做一些计算,RDD 就是 Spark 用来存储和操作这些数据的一种方式。它有两个基本操作:转换操作(就像是加工数据)和 行动操作(获取结果)
RDD案例
基于集合创建RDD
import lombok.extern.slf4j.Slf4j;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.sql.SparkSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.List;
/**
* spark 案例
*/
@Slf4j
@Component
public class DemoTimer {
@Autowired
JavaSparkContext javaSparkContext;
@Autowired
SparkSession sparkSession;
/**
* 创建 RDD 算子
*/
@PostConstruct
public void createRDD() {
// 从集合创建 RDD
List<String> lists = Arrays.asList("hello", "spark", "hi", "spark", "hadoop");
JavaRDD<String> parallelize = javaSparkContext.parallelize(lists); // 创建RDD
parallelize.collect().forEach(System.out::println); // 打印
}
}
输出结果:
RDD存入外部文件中
将RDD存入外部文件,用于观察文件结果和分区结果。txt文件数等于默认分区数。从结果中看出默认分区为4个。
注意:存放结果的文件夹路径必须没有被创建。
以下案例中,将基于集合生成的RDD保存到saveRddDemo文件夹中。
package www.zhangxiaosan.top.timer;
import lombok.extern.slf4j.Slf4j;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.sql.SparkSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.List;
/**
* spark 案例
*/
@Slf4j
@Component
public class DemoTimer {
@Autowired
JavaSparkContext javaSparkContext;
@Autowired
SparkSession sparkSession;
/**
* 创建 RDD 算子
*/
@PostConstruct
public void createRDD() {
// 从集合创建 RDD
List<String> lists = Arrays.asList("hello", "spark", "hi", "spark", "hadoop");
// parallelize(): 创建RDD,RDD中创建默认分区数
// parallelize( 元素, 分区数): 创建RDD,RDD中指定分区数
JavaRDD<String> parallelize = javaSparkContext.parallelize(lists); // 创建RDD
parallelize.collect().forEach(System.out::println); // 打印
// 存储的目录文件夹路径。此处为项目中的路径且目录必须为不存在的路径。
String fileSavePath="I:\\zhang\\SpringBootSparkDemo\\src\\main\\resources\\saveRddDemo";
parallelize.saveAsTextFile(fileSavePath);// 开始将RDD保存到文件中
}
}
运行结果:
在文件夹中存放的是运行程序生成的文件。如下图。
_SUCCESS文件:成功标记
part-XXX 文件:保存的数据文件 ,结果中有4个文件,说明默认分区为4个。
转换算子 操作
转换算子(Transformation)是指那些返回一个新的 RDD 的操作。转换算子不会立即执行计算,而是构建一个执行计划,只有当行动算子(Action)触发计算时,转换算子的操作才会实际执行。转换算子可以用来处理和转换数据,比如映射、过滤、聚合等。
map 操作
说明
map() 方法传入一个函数作为参数。map() 方法会将RDD中的元素逐一进行调用,函数的参数即是RDD的元素。 如:map( 函数( RDD元素 ) )。 map() 方法会返回一个新的RDD。
案例
将RDD中的每个元素都拼接上字符串 “ say hi ”
package www.zhangxiaosan.top.timer;
import lombok.extern.slf4j.Slf4j;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.sql.SparkSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.List;
/**
* spark 案例
*/
@Slf4j
@Component
public class DemoTimer {
@Autowired
JavaSparkContext javaSparkContext;
@Autowired
SparkSession sparkSession;
/**
* 创建 RDD 算子
*/
@PostConstruct
public void createRDD() {
// 从集合创建 RDD
List<String> lists = Arrays.asList("张三", "李四", "王五");
JavaRDD<String> parallelize = javaSparkContext.parallelize(lists); // 创建RDD
// lambda表达式传入匿名函数,进行元素拼接字符。
// item 表示RDD中的元素
parallelize = parallelize.map(item -> item + " say hi");
parallelize.collect().forEach(System.out::println); // 打印
}
}
输出结果:
flatMap操作
说明
flatMap() 方法传入一个函数作为参数 。flatMap() 方法会将RDD中的元素逐一进行调用,函数的参数即是RDD的元素。 如:flatMap( 函数( RDD元素 ) )。 flatMap() 方法会返回一个新的RDD。
flatMap() 方法 会将 RDD的元素扁平化处理成一个集合。
例如:
假设你有一个箱子,箱子里面放着几个小盒子,每个小盒子里又有一些玩具。flatMap 就是一个工具,它能帮你把每个小盒子里的玩具拿出来,直接放进一个大盒子里,最终把所有玩具放在一个地方。
每个小盒子里的玩具可以不止一个,甚至可能没有玩具(比如有的盒子是空的)。flatMap 会把每个盒子里的玩具都拿出来,放到一个大盒子里,最终得到一个扁平的大盒子,里面是所有玩具。
案例
将集合:[ [1, 2, 3, 4, 5],[hello, spark],[张三, 李四] ]
扁平化处理成:[ 1, 2, 3, 4, 5, hello, spark, 张三, 李四]
import lombok.extern.slf4j.Slf4j;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.sql.SparkSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.List;
/**
* spark 案例
*/
@Slf4j
@Component
public class DemoTimer {
@Autowired
JavaSparkContext javaSparkContext;
@Autowired
SparkSession sparkSession;
@PostConstruct
public void flatMapDemo() {
// 声明集合:[ [1, 2, 3, 4, 5],[hello, spark],[张三, 李四] ]
List<List<String>> arrs = Arrays.asList(
Arrays.asList("1", "2", "3", "4", "5"),
Arrays.asList("hello", "spark"),
Arrays.asList("张三", "李四")
);
//输出声明的集合呢容
System.out.println("原始集合打印:");
arrs.forEach(item -> System.out.print(" " + item));
// 分隔符
System.out.println();
System.out.println("-----------");
System.out.println("flatMap操作后:");
// 创建集合的RDD
JavaRDD<List<String>> parallelize = javaSparkContext.parallelize(arrs);
// flatMap操作
List<String> collect = parallelize.flatMap(i -> i.iterator()).collect();
// 打印 flatMap操作 后的集合
collect.forEach(item -> System.out.print(" " + item));
System.out.println();
}
}
filter 操作
说明
filter() 方法传入一个函数作为参数,函数返回值只能为Boolean值。filter() 方法会将RDD中的元素逐一进行调用,函数的参数即是RDD的元素。 如:filter( 函数( RDD元素 ) )。 filter() 方法会返回一个新的RDD。filter() 将RDD元素中满足条件的元素保留,即函数返回为true的元素;RDD中不满足条件的元素,即函数返回为false的元素过滤。
案例
过滤单数,保留双数
import lombok.extern.slf4j.Slf4j;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.sql.SparkSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct