本文章主要通过java代码实现spark常用的action操作
本文主要通过java代码实现常用的spark的action操作
1 reduce
private static void reduce() { // 创建SparkConf和JavaSparkContext SparkConf conf = new SparkConf() .setAppName("reduce") .setMaster("local"); JavaSparkContext sc = new JavaSparkContext(conf); // 有一个集合,里面有1到10,10个数字,现在要对10个数字进行累加 List<Integer> numberList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); JavaRDD<Integer> numbers = sc.parallelize(numberList); // 使用reduce操作对集合中的数字进行累加 // reduce操作的原理: // 首先将第一个和第二个元素,传入call()方法,进行计算,会获取一个结果,比如1 + 2 = 3 // 接着将该结果与下一个元素传入call()方法,进行计算,比如3 + 3 = 6 // 以此类推 // 所以reduce操作的本质,就是聚合,将多个元素聚合成一个元素 int sum = numbers.reduce(new Function2<Integer, Integer, Integer>() { private static final long serialVersionUID = 1L; @Override public Integer call(Integer v1, Integer v2) throws Exception { return v1 + v2; } }); System.out.println(sum); // 关闭JavaSparkContext sc.close(); }
2 collect
private static void collect() { // 创建SparkConf和JavaSparkContext SparkConf conf = new SparkConf() .setAppName("collect") .setMaster("local"); JavaSparkContext sc = new JavaSparkContext(conf); // 有一个集合,里面有1到10,10个数字,现在要对10个数字进行累加 List<Integer> numberList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); JavaRDD<Integer> numbers = sc.parallelize(numberList); // 使用map操作将集合中所有数字乘以2 JavaRDD<Integer> doubleNumbers = numbers.map( new Function<Integer, Integer>() { private static final long serialVersionUID = 1L; @Override public Integer call(Integer v1) throws Exception { return v1 * 2; } }); // 不用foreach action操作,在远程集群上遍历rdd中的元素 // 而使用collect操作,将分布在远程集群上的doubleNumbers RDD的数据拉取到本地 // 这种方式,一般不建议使用,因为如果rdd中的数据量比较大的话,比如超过1万条 // 那么性能会比较差,因为要从远程走大量的网络传输,将数据获取到本地 // 此外,除了性能差,还可能在rdd中数据量特别大的情况下,发生oom异常,内存溢出 // 因此,通常,还是推荐使用foreach action操作,来对最终的rdd元素进行处理 List<Integer> doubleNumberList = doubleNumbers.collect(); for(Integer num : doubleNumberList) { System.out.println(num); } // 关闭JavaSparkContext sc.close(); }
3 count
private static void count() { // 创建SparkConf和JavaSparkContext SparkConf conf = new SparkConf() .setAppName("count") .setMaster("local"); JavaSparkContext sc = new JavaSparkContext(conf); // 有一个集合,里面有1到10,10个数字,现在要对10个数字进行累加 List<Integer> numberList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); JavaRDD<Integer> numbers = sc.parallelize(numberList); // 对rdd使用count操作,统计它有多少个元素 long count = numbers.count(); System.out.println(count); // 关闭JavaSparkContext sc.close(); }
4 take
private static void take() { // 创建SparkConf和JavaSparkContext SparkConf conf = new SparkConf() .setAppName("take") .setMaster("local"); JavaSparkContext sc = new JavaSparkContext(conf); // 有一个集合,里面有1到10,10个数字,现在要对10个数字进行累加 List<Integer> numberList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); JavaRDD<Integer> numbers = sc.parallelize(numberList); // 对rdd使用count操作,统计它有多少个元素 // take操作,与collect类似,也是从远程集群上,获取rdd的数据 // 但是collect是获取rdd的所有数据,take只是获取前n个数据 List<Integer> top3Numbers = numbers.take(3); for(Integer num : top3Numbers) { System.out.println(num); } // 关闭JavaSparkContext sc.close(); }
5 saveastextfile
private static void saveAsTextFile() { // 创建SparkConf和JavaSparkContext SparkConf conf = new SparkConf() .setAppName("saveAsTextFile"); JavaSparkContext sc = new JavaSparkContext(conf); // 有一个集合,里面有1到10,10个数字,现在要对10个数字进行累加 List<Integer> numberList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); JavaRDD<Integer> numbers = sc.parallelize(numberList); // 使用map操作将集合中所有数字乘以2 JavaRDD<Integer> doubleNumbers = numbers.map( new Function<Integer, Integer>() { private static final long serialVersionUID = 1L; @Override public Integer call(Integer v1) throws Exception { return v1 * 2; } }); // 直接将rdd中的数据,保存在HFDS文件中 // 但是要注意,我们这里只能指定文件夹,也就是目录 // 那么实际上,会保存为目录中的/double_number.txt/part-00000文件 doubleNumbers.saveAsTextFile("hdfs://spark1:9000/double_number.txt"); // 关闭JavaSparkContext sc.close(); }
6 countbykey
private static void countByKey() { // 创建SparkConf SparkConf conf = new SparkConf() .setAppName("countByKey") .setMaster("local"); // 创建JavaSparkContext JavaSparkContext sc = new JavaSparkContext(conf); // 模拟集合 List<Tuple2<String, String>> scoreList = Arrays.asList( new Tuple2<String, String>("class1", "leo"), new Tuple2<String, String>("class2", "jack"), new Tuple2<String, String>("class1", "marry"), new Tuple2<String, String>("class2", "tom"), new Tuple2<String, String>("class2", "david")); // 并行化集合,创建JavaPairRDD JavaPairRDD<String, String> students = sc.parallelizePairs(scoreList); // 对rdd应用countByKey操作,统计每个班级的学生人数,也就是统计每个key对应的元素个数 // 这就是countByKey的作用 // countByKey返回的类型,直接就是Map<String, Object> Map<String, Object> studentCounts = students.countByKey(); for(Map.Entry<String, Object> studentCount : studentCounts.entrySet()) { System.out.println(studentCount.getKey() + ": " + studentCount.getValue()); } // 关闭JavaSparkContext sc.close(); }
7 groupbykey
/** * groupByKey案例:按照班级对成绩进行分组 */ private static void groupByKey() { // 创建SparkConf SparkConf conf = new SparkConf() .setAppName("groupByKey") .setMaster("local"); // 创建JavaSparkContext JavaSparkContext sc = new JavaSparkContext(conf); // 模拟集合 List<Tuple2<String, Integer>> scoreList = Arrays.asList( new Tuple2<String, Integer>("class1", 80), new Tuple2<String, Integer>("class2", 75), new Tuple2<String, Integer>("class1", 90), new Tuple2<String, Integer>("class2", 65)); // 并行化集合,创建JavaPairRDD JavaPairRDD<String, Integer> scores = sc.parallelizePairs(scoreList); // 针对scores RDD,执行groupByKey算子,对每个班级的成绩进行分组 // groupByKey算子,返回的还是JavaPairRDD // 但是,JavaPairRDD的第一个泛型类型不变,第二个泛型类型变成Iterable这种集合类型 // 也就是说,按照了key进行分组,那么每个key可能都会有多个value,此时多个value聚合成了Iterable // 那么接下来,我们是不是就可以通过groupedScores这种JavaPairRDD,很方便地处理某个分组内的数据 JavaPairRDD<String, Iterable<Integer>> groupedScores = scores.groupByKey(); // 打印groupedScores RDD groupedScores.foreach(new VoidFunction<Tuple2<String,Iterable<Integer>>>() { private static final long serialVersionUID = 1L; @Override public void call(Tuple2<String, Iterable<Integer>> t) throws Exception { System.out.println("class: " + t._1); Iterator<Integer> ite = t._2.iterator(); while(ite.hasNext()) { System.out.println(ite.next()); } System.out.println("=============================="); } }); // 关闭JavaSparkContext sc.close(); }
8 reducebykey
private static void reduceByKey() { // 创建SparkConf SparkConf conf = new SparkConf() .setAppName("reduceByKey") .setMaster("local"); // 创建JavaSparkContext JavaSparkContext sc = new JavaSparkContext(conf); // 模拟集合 List<Tuple2<String, Integer>> scoreList = Arrays.asList( new Tuple2<String, Integer>("class1", 80), new Tuple2<String, Integer>("class2", 75), new Tuple2<String, Integer>("class1", 90), new Tuple2<String, Integer>("class2", 65)); // 并行化集合,创建JavaPairRDD JavaPairRDD<String, Integer> scores = sc.parallelizePairs(scoreList); // 针对scores RDD,执行reduceByKey算子 // reduceByKey,接收的参数是Function2类型,它有三个泛型参数,实际上代表了三个值 // 第一个泛型类型和第二个泛型类型,代表了原始RDD中的元素的value的类型 // 因此对每个key进行reduce,都会依次将第一个、第二个value传入,将值再与第三个value传入 // 因此此处,会自动定义两个泛型类型,代表call()方法的两个传入参数的类型 // 第三个泛型类型,代表了每次reduce操作返回的值的类型,默认也是与原始RDD的value类型相同的 // reduceByKey算法返回的RDD,还是JavaPairRDD<key, value> JavaPairRDD<String, Integer> totalScores = scores.reduceByKey( new Function2<Integer, Integer, Integer>() { private static final long serialVersionUID = 1L; // 对每个key,都会将其value,依次传入call方法 // 从而聚合出每个key对应的一个value // 然后,将每个key对应的一个value,组合成一个Tuple2,作为新RDD的元素 @Override public Integer call(Integer v1, Integer v2) throws Exception { return v1 + v2; } }); // 打印totalScores RDD totalScores.foreach(new VoidFunction<Tuple2<String,Integer>>() { private static final long serialVersionUID = 1L; @Override public void call(Tuple2<String, Integer> t) throws Exception { System.out.println(t._1 + ": " + t._2); } }); // 关闭JavaSparkContext sc.close(); }