使用Java,Scala和spark-shell开发wordcount程序

pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>groupId</groupId>
  7. <artifactId>TestES</artifactId>
  8. <version>1.0-SNAPSHOT</version>
  9. <name>es-core-first</name>
  10. <url>http://maven.apache.org</url>
  11. <properties>
  12. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  13. </properties>
  14. <dependencies>
  15. <dependency>
  16. <groupId>org.elasticsearch.client</groupId>
  17. <artifactId>transport</artifactId>
  18. <version>6.7.0</version>
  19. </dependency>
  20. <dependency>
  21. <groupId>org.apache.logging.log4j</groupId>
  22. <artifactId>log4j-api</artifactId>
  23. <version>2.7</version>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.apache.logging.log4j</groupId>
  27. <artifactId>log4j-core</artifactId>
  28. <version>2.7</version>
  29. </dependency>
  30. <dependency>
  31. <groupId>org.apache.hbase</groupId>
  32. <artifactId>hbase-client</artifactId>
  33. <version>1.2.6</version>
  34. </dependency>
  35. <dependency>
  36. <groupId>org.apache.spark</groupId>
  37. <artifactId>spark-core_2.10</artifactId>
  38. <version>1.6.0</version>
  39. </dependency>
  40. </dependencies>
  41. </project>

Java版

  1. import org.apache.spark.SparkConf;
  2. import org.apache.spark.api.java.JavaPairRDD;
  3. import org.apache.spark.api.java.JavaRDD;
  4. import org.apache.spark.api.java.JavaSparkContext;
  5. import org.apache.spark.api.java.function.FlatMapFunction;
  6. import org.apache.spark.api.java.function.Function2;
  7. import org.apache.spark.api.java.function.PairFunction;
  8. import org.apache.spark.api.java.function.VoidFunction;
  9. import scala.Tuple2;
  10. import java.util.Arrays;
  11. public class WordCountLocal {
  12. public static void main(String[] args) {
  13. // 编写Spark应用程序
  14. // 本地执行,是可以执行在eclipse中的main方法中,执行的
  15. // 第一步:创建SparkConf对象,设置Spark应用的配置信息
  16. // 使用setMaster()可以设置Spark应用程序要连接的Spark集群的master节点的url
  17. // 但是如果设置为local则代表,在本地运行
  18. SparkConf conf = new SparkConf()
  19. .setAppName("WordCountLocal")
  20. .setMaster("local");
  21. // 第二步:创建JavaSparkContext对象
  22. // 在Spark中,SparkContext是Spark所有功能的一个入口,你无论是用java、scala,甚至是python编写
  23. // 都必须要有一个SparkContext,它的主要作用,包括初始化Spark应用程序所需的一些核心组件,包括
  24. // 调度器(DAGSchedule、TaskScheduler),还会去到Spark Master节点上进行注册,等等
  25. // 一句话,SparkContext,是Spark应用中,可以说是最最重要的一个对象
  26. // 但是呢,在Spark中,编写不同类型的Spark应用程序,使用的SparkContext是不同的,如果使用scala,
  27. // 使用的就是原生的SparkContext对象
  28. // 但是如果使用Java,那么就是JavaSparkContext对象
  29. // 如果是开发Spark SQL程序,那么就是SQLContext、HiveContext
  30. // 如果是开发Spark Streaming程序,那么就是它独有的SparkContext
  31. // 以此类推
  32. JavaSparkContext sc = new JavaSparkContext(conf);
  33. // 第三步:要针对输入源(hdfs文件、本地文件,等等),创建一个初始的RDD
  34. // 输入源中的数据会打散,分配到RDD的每个partition中,从而形成一个初始的分布式的数据集
  35. // 我们这里呢,因为是本地测试,所以呢,就是针对本地文件
  36. // SparkContext中,用于根据文件类型的输入源创建RDD的方法,叫做textFile()方法
  37. // 在Java中,创建的普通RDD,都叫做JavaRDD
  38. // 在这里呢,RDD中,有元素这种概念,如果是hdfs或者本地文件呢,创建的RDD,每一个元素就相当于
  39. // 是文件里的一行
  40. JavaRDD<String> lines = sc.textFile("/Users/gaozhen/tmp/spark.txt");
  41. // 第四步:对初始RDD进行transformation操作,也就是一些计算操作
  42. // 通常操作会通过创建function,并配合RDD的map、flatMap等算子来执行
  43. // function,通常,如果比较简单,则创建指定Function的匿名内部类
  44. // 但是如果function比较复杂,则会单独创建一个类,作为实现这个function接口的类
  45. // 先将每一行拆分成单个的单词
  46. // FlatMapFunction,有两个泛型参数,分别代表了输入和输出类型
  47. // 我们这里呢,输入肯定是String,因为是一行一行的文本,输出,其实也是String,因为是每一行的文本
  48. // 这里先简要介绍flatMap算子的作用,其实就是,将RDD的一个元素,给拆分成一个或多个元素
  49. JavaRDD<String> words = lines.flatMap(new FlatMapFunction<String, String>() {
  50. private static final long serialVersionUID = 1L;
  51. // @Override
  52. public Iterable<String> call(String line) throws Exception {
  53. return Arrays.asList(line.split(" "));
  54. }
  55. });
  56. // 接着,需要将每一个单词,映射为(单词, 1)的这种格式
  57. // 因为只有这样,后面才能根据单词作为key,来进行每个单词的出现次数的累加
  58. // mapToPair,其实就是将每个元素,映射为一个(v1,v2)这样的Tuple2类型的元素
  59. // 如果大家还记得scala里面讲的tuple,那么没错,这里的tuple2就是scala类型,包含了两个值
  60. // mapToPair这个算子,要求的是与PairFunction配合使用,第一个泛型参数代表了输入类型
  61. // 第二个和第三个泛型参数,代表的输出的Tuple2的第一个值和第二个值的类型
  62. // JavaPairRDD的两个泛型参数,分别代表了tuple元素的第一个值和第二个值的类型
  63. JavaPairRDD<String, Integer> pairs = words.mapToPair(
  64. new PairFunction<String, String, Integer>() {
  65. private static final long serialVersionUID = 1L;
  66. // @Override
  67. public Tuple2<String, Integer> call(String word) throws Exception {
  68. return new Tuple2<String, Integer>(word, 1);
  69. }
  70. });
  71. // 接着,需要以单词作为key,统计每个单词出现的次数
  72. // 这里要使用reduceByKey这个算子,对每个key对应的value,都进行reduce操作
  73. // 比如JavaPairRDD中有几个元素,分别为(hello, 1) (hello, 1) (hello, 1) (world, 1)
  74. // reduce操作,相当于是把第一个值和第二个值进行计算,然后再将结果与第三个值进行计算
  75. // 比如这里的hello,那么就相当于是,首先是1 + 1 = 2,然后再将2 + 1 = 3
  76. // 最后返回的JavaPairRDD中的元素,也是tuple,但是第一个值就是每个key,第二个值就是key的value
  77. // reduce之后的结果,相当于就是每个单词出现的次数
  78. JavaPairRDD<String, Integer> wordCounts = pairs.reduceByKey(
  79. new Function2<Integer, Integer, Integer>() {
  80. private static final long serialVersionUID = 1L;
  81. // @Override
  82. public Integer call(Integer v1, Integer v2) throws Exception {
  83. return v1 + v2;
  84. }
  85. });
  86. // 到这里为止,我们通过几个Spark算子操作,已经统计出了单词的次数
  87. // 但是,之前我们使用的flatMap、mapToPair、reduceByKey这种操作,都叫做transformation操作
  88. // 一个Spark应用中,光是有transformation操作,是不行的,是不会执行的,必须要有一种叫做action
  89. // 接着,最后,可以使用一种叫做action操作的,比如说,foreach,来触发程序的执行
  90. wordCounts.foreach(new VoidFunction<Tuple2<String,Integer>>() {
  91. private static final long serialVersionUID = 1L;
  92. // @Override
  93. public void call(Tuple2<String, Integer> wordCount) throws Exception {
  94. System.out.println(wordCount._1 + " appeared " + wordCount._2 + " times.");
  95. }
  96. });
  97. sc.close();
  98. }
  99. }

scala版本:

  1. import org.apache.spark.{SparkConf, SparkContext}
  2. object WordCount {
  3. def main(args: Array[String]) {
  4. val conf = new SparkConf()
  5. .setAppName("WordCount").setMaster("local");
  6. val sc = new SparkContext(conf)
  7. val lines = sc.textFile("/Users/gaozhen/tmp/spark.txt", 1);
  8. val words = lines.flatMap { line => line.split(" ") }
  9. val pairs = words.map { word => (word, 1) }
  10. val wordCounts = pairs.reduceByKey { _ + _ }
  11. wordCounts.foreach(wordCount => println(wordCount._1 + " appeared " + wordCount._2 + " times."))
  12. }
  13. }

遇到的问题:

  1. Exception in thread "main" java.lang.NoSuchMethodError: scala.Predef$.refArrayOps([Ljava/lang/Object;)Lscala/collection/mutable/ArrayOps;
  2. 原因: 使用的spark版本是1.6的,spark自身带的Scala版本是2.10.* 出现sparkScala版本不一致导致的
  3. 解决方案:
  4. Scala版本降到2.10.*版本

Spark核心编程:transformation操作开发实战

map 将集合中每个元素乘以2

Java版

  1. private static void map() {
  2. // 创建SparkConf
  3. SparkConf conf = new SparkConf()
  4. .setAppName("map")
  5. .setMaster("local");
  6. // 创建JavaSparkContext
  7. JavaSparkContext sc = new JavaSparkContext(conf);
  8. // 构造集合
  9. List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
  10. // 并行化集合,创建初始RDD
  11. JavaRDD<Integer> numberRDD = sc.parallelize(numbers);
  12. // 使用map算子,将集合中的每个元素都乘以2
  13. // map算子,是对任何类型的RDD,都可以调用的
  14. // 在java中,map算子接收的参数是Function对象
  15. // 创建的Function对象,一定会让你设置第二个泛型参数,这个泛型类型,就是返回的新元素的类型
  16. // 同时call()方法的返回类型,也必须与第二个泛型类型同步
  17. // 在call()方法内部,就可以对原始RDD中的每一个元素进行各种处理和计算,并返回一个新的元素
  18. // 所有新的元素就会组成一个新的RDD
  19. JavaRDD<Integer> multipleNumberRDD = numberRDD.map(
  20. new Function<Integer, Integer>() {
  21. private static final long serialVersionUID = 1L;
  22. // 传入call()方法的,就是1,2,3,4,5
  23. // 返回的就是2,4,6,8,10
  24. @Override
  25. public Integer call(Integer v1) throws Exception {
  26. return v1 * 2;
  27. }
  28. });
  29. // 打印新的RDD
  30. multipleNumberRDD.foreach(new VoidFunction<Integer>() {
  31. private static final long serialVersionUID = 1L;
  32. @Override
  33. public void call(Integer t) throws Exception {
  34. System.out.println(t);
  35. }
  36. });
  37. // 关闭JavaSparkContext
  38. sc.close();
  39. }

Scala版

  1. def map(): Unit = {
  2. val conf = new SparkConf().setAppName("map").setMaster("local");
  3. val sc = new SparkContext(conf);
  4. val numbers = Array(1,2,3,4,5);
  5. val numberRdd = sc.parallelize(numbers, 1);
  6. val multipleNumberRdd = numberRdd.map{num => num*2}
  7. multipleNumberRdd.foreach(num=>println(num))
  8. }

filter:过滤出集合中的偶数

java版本

  1. /**
  2. * filter算子案例:过滤集合中的偶数
  3. */
  4. private static void filter() {
  5. // 创建SparkConf
  6. SparkConf conf = new SparkConf()
  7. .setAppName("filter")
  8. .setMaster("local");
  9. // 创建JavaSparkContext
  10. JavaSparkContext sc = new JavaSparkContext(conf);
  11. // 模拟集合
  12. List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
  13. // 并行化集合,创建初始RDD
  14. JavaRDD<Integer> numberRDD = sc.parallelize(numbers);
  15. // 对初始RDD执行filter算子,过滤出其中的偶数
  16. // filter算子,传入的也是Function,其他的使用注意点,实际上和map是一样的
  17. // 但是,唯一的不同,就是call()方法的返回类型是Boolean
  18. // 每一个初始RDD中的元素,都会传入call()方法,此时你可以执行各种自定义的计算逻辑
  19. // 来判断这个元素是否是你想要的
  20. // 如果你想在新的RDD中保留这个元素,那么就返回true;否则,不想保留这个元素,返回false
  21. JavaRDD<Integer> evenNumberRDD = numberRDD.filter(
  22. new Function<Integer, Boolean>() {
  23. private static final long serialVersionUID = 1L;
  24. // 在这里,1到10,都会传入进来
  25. // 但是根据我们的逻辑,只有2,4,6,8,10这几个偶数,会返回true
  26. // 所以,只有偶数会保留下来,放在新的RDD中
  27. @Override
  28. public Boolean call(Integer v1) throws Exception {
  29. return v1 % 2 == 0;
  30. }
  31. });
  32. // 打印新的RDD
  33. evenNumberRDD.foreach(new VoidFunction<Integer>() {
  34. private static final long serialVersionUID = 1L;
  35. @Override
  36. public void call(Integer t) throws Exception {
  37. System.out.println(t);
  38. }
  39. });
  40. // 关闭JavaSparkContext
  41. sc.close();
  42. }

scala 版本

  1. def filter(): Unit = {
  2. val conf = new SparkConf().setAppName("filter").setMaster("local");
  3. val sc = new SparkContext(conf);
  4. val numbers = Array(1,2,3,4,5,6,7,8);
  5. val numberRdd = sc.parallelize(numbers,1);
  6. val evenNumber = numberRdd.filter{num => num % 2 == 0}
  7. evenNumber.foreach(num => println(num))
  8. }

flatMap:将行拆分为单词

java版本

  1. /**
  2. * flatMap案例:将文本行拆分为多个单词
  3. */
  4. private static void flatMap() {
  5. // 创建SparkConf
  6. SparkConf conf = new SparkConf()
  7. .setAppName("flatMap")
  8. .setMaster("local");
  9. // 创建JavaSparkContext
  10. JavaSparkContext sc = new JavaSparkContext(conf);
  11. // 构造集合
  12. List<String> lineList = Arrays.asList("hello you", "hello me", "hello world");
  13. // 并行化集合,创建RDD
  14. JavaRDD<String> lines = sc.parallelize(lineList);
  15. // 对RDD执行flatMap算子,将每一行文本,拆分为多个单词
  16. // flatMap算子,在java中,接收的参数是FlatMapFunction
  17. // 我们需要自己定义FlatMapFunction的第二个泛型类型,即,代表了返回的新元素的类型
  18. // call()方法,返回的类型,不是U,而是Iterable<U>,这里的U也与第二个泛型类型相同
  19. // flatMap其实就是,接收原始RDD中的每个元素,并进行各种逻辑的计算和处理,返回可以返回多个元素
  20. // 多个元素,即封装在Iterable集合中,可以使用ArrayList等集合
  21. // 新的RDD中,即封装了所有的新元素;也就是说,新的RDD的大小一定是 >= 原始RDD的大小
  22. JavaRDD<String> words = lines.flatMap(new FlatMapFunction<String, String>() {
  23. private static final long serialVersionUID = 1L;
  24. // 在这里会,比如,传入第一行,hello you
  25. // 返回的是一个Iterable<String>(hello, you)
  26. @Override
  27. public Iterable<String> call(String t) throws Exception {
  28. return Arrays.asList(t.split(" "));
  29. }
  30. });
  31. // 打印新的RDD
  32. words.foreach(new VoidFunction<String>() {
  33. private static final long serialVersionUID = 1L;
  34. @Override
  35. public void call(String t) throws Exception {
  36. System.out.println(t);
  37. }
  38. });
  39. // 关闭JavaSparkContext
  40. sc.close();
  41. }

scala 版本

  1. def flatMap(): Unit = {
  2. val conf = new SparkConf();
  3. conf.setAppName("flatMap");
  4. conf.setMaster("local");
  5. val sc = new SparkContext(conf);
  6. val lineArray = Array("hello you", "cbd dfe sfewfw");
  7. val lines = sc.parallelize(lineArray);
  8. val words = lines.flatMap(line=>line.split(" "));
  9. words.foreach(word=>println(word))
  10. }

groupByKey案例:按照班级对成绩进行分组

java 版本

  1. /**
  2. * groupByKey案例:按照班级对成绩进行分组
  3. */
  4. private static void groupByKey() {
  5. // 创建SparkConf
  6. SparkConf conf = new SparkConf()
  7. .setAppName("groupByKey")
  8. .setMaster("local");
  9. // 创建JavaSparkContext
  10. JavaSparkContext sc = new JavaSparkContext(conf);
  11. // 模拟集合
  12. List<Tuple2<String, Integer>> scoreList = Arrays.asList(
  13. new Tuple2<String, Integer>("class1", 80),
  14. new Tuple2<String, Integer>("class2", 75),
  15. new Tuple2<String, Integer>("class1", 90),
  16. new Tuple2<String, Integer>("class2", 65));
  17. // 并行化集合,创建JavaPairRDD
  18. JavaPairRDD<String, Integer> scores = sc.parallelizePairs(scoreList);
  19. // 针对scores RDD,执行groupByKey算子,对每个班级的成绩进行分组
  20. // groupByKey算子,返回的还是JavaPairRDD
  21. // 但是,JavaPairRDD的第一个泛型类型不变,第二个泛型类型变成Iterable这种集合类型
  22. // 也就是说,按照了key进行分组,那么每个key可能都会有多个value,此时多个value聚合成了Iterable
  23. // 那么接下来,我们是不是就可以通过groupedScores这种JavaPairRDD,很方便地处理某个分组内的数据
  24. JavaPairRDD<String, Iterable<Integer>> groupedScores = scores.groupByKey();
  25. // 打印groupedScores RDD
  26. groupedScores.foreach(new VoidFunction<Tuple2<String,Iterable<Integer>>>() {
  27. private static final long serialVersionUID = 1L;
  28. @Override
  29. public void call(Tuple2<String, Iterable<Integer>> t)
  30. throws Exception {
  31. System.out.println("class: " + t._1);
  32. Iterator<Integer> ite = t._2.iterator();
  33. while(ite.hasNext()) {
  34. System.out.println(ite.next());
  35. }
  36. System.out.println("==============================");
  37. }
  38. });
  39. // 关闭JavaSparkContext
  40. sc.close();
  41. }

scala 版本

  1. def groupByKey(): Unit ={
  2. val conf = new SparkConf().setAppName("groupByKey").setMaster("local");
  3. val sc = new SparkContext(conf);
  4. val scoreList = Array(Tuple2("class1",80), Tuple2("class2", 75), Tuple2("class1",40))
  5. val scores = sc.parallelize(scoreList, 1)
  6. val groupedScores = scores.groupByKey()
  7. groupedScores.foreach(score => {
  8. println(score._1)
  9. score._2.foreach( singleScore => println(singleScore))
  10. println("=============")
  11. })
  12. }

reduceByKey案例:统计每个班级的总分

Java版本

  1. /**
  2. * reduceByKey案例:统计每个班级的总分
  3. */
  4. private static void reduceByKey() {
  5. // 创建SparkConf
  6. SparkConf conf = new SparkConf()
  7. .setAppName("reduceByKey")
  8. .setMaster("local");
  9. // 创建JavaSparkContext
  10. JavaSparkContext sc = new JavaSparkContext(conf);
  11. // 模拟集合
  12. List<Tuple2<String, Integer>> scoreList = Arrays.asList(
  13. new Tuple2<String, Integer>("class1", 80),
  14. new Tuple2<String, Integer>("class2", 75),
  15. new Tuple2<String, Integer>("class1", 90),
  16. new Tuple2<String, Integer>("class2", 65));
  17. // 并行化集合,创建JavaPairRDD
  18. JavaPairRDD<String, Integer> scores = sc.parallelizePairs(scoreList);
  19. // 针对scores RDD,执行reduceByKey算子
  20. // reduceByKey,接收的参数是Function2类型,它有三个泛型参数,实际上代表了三个值
  21. // 第一个泛型类型和第二个泛型类型,代表了原始RDD中的元素的value的类型
  22. // 因此对每个key进行reduce,都会依次将第一个、第二个value传入,将值再与第三个value传入
  23. // 因此此处,会自动定义两个泛型类型,代表call()方法的两个传入参数的类型
  24. // 第三个泛型类型,代表了每次reduce操作返回的值的类型,默认也是与原始RDD的value类型相同的
  25. // reduceByKey算法返回的RDD,还是JavaPairRDD<key, value>
  26. JavaPairRDD<String, Integer> totalScores = scores.reduceByKey(
  27. new Function2<Integer, Integer, Integer>() {
  28. private static final long serialVersionUID = 1L;
  29. // 对每个key,都会将其value,依次传入call方法
  30. // 从而聚合出每个key对应的一个value
  31. // 然后,将每个key对应的一个value,组合成一个Tuple2,作为新RDD的元素
  32. @Override
  33. public Integer call(Integer v1, Integer v2) throws Exception {
  34. return v1 + v2;
  35. }
  36. });
  37. // 打印totalScores RDD
  38. totalScores.foreach(new VoidFunction<Tuple2<String,Integer>>() {
  39. private static final long serialVersionUID = 1L;
  40. @Override
  41. public void call(Tuple2<String, Integer> t) throws Exception {
  42. System.out.println(t._1 + ": " + t._2);
  43. }
  44. });
  45. // 关闭JavaSparkContext
  46. sc.close();
  47. }

scala 版本

  1. def reduceByKey(): Unit = {
  2. val cof = new SparkConf().setAppName("recudeByKey").setMaster("local");
  3. val sc = new SparkContext(cof);
  4. val scoreList = Array(Tuple2("class1", 80), Tuple2("class2", 54),
  5. Tuple2("class2", 98))
  6. val scores = sc.parallelize(scoreList,1)
  7. val totalScores = scores.reduceByKey(_+_)
  8. totalScores.foreach(classScore => println(classScore._1+ ":" + classScore._2))
  9. }

sortByKey案例:按照学生分数进行排序
java 版本

  1. /**
  2. * sortByKey案例:按照学生分数进行排序
  3. */
  4. private static void sortByKey() {
  5. // 创建SparkConf
  6. SparkConf conf = new SparkConf()
  7. .setAppName("sortByKey")
  8. .setMaster("local");
  9. // 创建JavaSparkContext
  10. JavaSparkContext sc = new JavaSparkContext(conf);
  11. // 模拟集合
  12. List<Tuple2<Integer, String>> scoreList = Arrays.asList(
  13. new Tuple2<Integer, String>(65, "leo"),
  14. new Tuple2<Integer, String>(50, "tom"),
  15. new Tuple2<Integer, String>(100, "marry"),
  16. new Tuple2<Integer, String>(80, "jack"));
  17. // 并行化集合,创建RDD
  18. JavaPairRDD<Integer, String> scores = sc.parallelizePairs(scoreList);
  19. // 对scores RDD执行sortByKey算子
  20. // sortByKey其实就是根据key进行排序,可以手动指定升序,或者降序
  21. // 返回的,还是JavaPairRDD,其中的元素内容,都是和原始的RDD一模一样的
  22. // 但是就是RDD中的元素的顺序,不同了
  23. JavaPairRDD<Integer, String> sortedScores = scores.sortByKey(false);
  24. // 打印sortedScored RDD
  25. sortedScores.foreach(new VoidFunction<Tuple2<Integer,String>>() {
  26. private static final long serialVersionUID = 1L;
  27. @Override
  28. public void call(Tuple2<Integer, String> t) throws Exception {
  29. System.out.println(t._1 + ": " + t._2);
  30. }
  31. });
  32. // 关闭JavaSparkContext
  33. sc.close();
  34. }

Scala版本

  1. def sortByKey(): Unit = {
  2. val conf = new SparkConf().setAppName("sortByKey").setMaster("local");
  3. val sc = new SparkContext(conf)
  4. val scoresList = Array(Tuple2(54,"tome"), Tuple2(76, "tome2"));
  5. val socres = sc.parallelize(scoresList, 1)
  6. val sortedScores = socres.sortByKey(false);
  7. sortedScores.foreach(studentScore => println(studentScore._1 + ":" + studentScore._2))
  8. }

join案例:打印学生成绩

java 版本

  1. /**
  2. * join案例:打印学生成绩
  3. */
  4. private static void join() {
  5. // 创建SparkConf
  6. SparkConf conf = new SparkConf()
  7. .setAppName("join")
  8. .setMaster("local");
  9. // 创建JavaSparkContext
  10. JavaSparkContext sc = new JavaSparkContext(conf);
  11. // 模拟集合
  12. List<Tuple2<Integer, String>> studentList = Arrays.asList(
  13. new Tuple2<Integer, String>(1, "leo"),
  14. new Tuple2<Integer, String>(2, "jack"),
  15. new Tuple2<Integer, String>(3, "tom"));
  16. List<Tuple2<Integer, Integer>> scoreList = Arrays.asList(
  17. new Tuple2<Integer, Integer>(1, 100),
  18. new Tuple2<Integer, Integer>(2, 90),
  19. new Tuple2<Integer, Integer>(3, 60));
  20. // 并行化两个RDD
  21. JavaPairRDD<Integer, String> students = sc.parallelizePairs(studentList);
  22. JavaPairRDD<Integer, Integer> scores = sc.parallelizePairs(scoreList);
  23. // 使用join算子关联两个RDD
  24. // join以后,还是会根据key进行join,并返回JavaPairRDD
  25. // 但是JavaPairRDD的第一个泛型类型,之前两个JavaPairRDD的key的类型,因为是通过key进行join的
  26. // 第二个泛型类型,是Tuple2<v1, v2>的类型,Tuple2的两个泛型分别为原始RDD的value的类型
  27. // join,就返回的RDD的每一个元素,就是通过key join上的一个pair
  28. // 什么意思呢?比如有(1, 1) (1, 2) (1, 3)的一个RDD
  29. // 还有一个(1, 4) (2, 1) (2, 2)的一个RDD
  30. // join以后,实际上会得到(1 (1, 4)) (1, (2, 4)) (1, (3, 4))
  31. JavaPairRDD<Integer, Tuple2<String, Integer>> studentScores = students.join(scores);
  32. // 打印studnetScores RDD
  33. studentScores.foreach(
  34. new VoidFunction<Tuple2<Integer,Tuple2<String,Integer>>>() {
  35. private static final long serialVersionUID = 1L;
  36. @Override
  37. public void call(Tuple2<Integer, Tuple2<String, Integer>> t)
  38. throws Exception {
  39. System.out.println("student id: " + t._1);
  40. System.out.println("student name: " + t._2._1);
  41. System.out.println("student score: " + t._2._2);
  42. System.out.println("===============================");
  43. }
  44. });
  45. // 关闭JavaSparkContext
  46. sc.close();
  47. }

Scala版本

  1. def join(): Unit = {
  2. val conf = new SparkConf();
  3. conf.setAppName("join");
  4. conf.setMaster("local");
  5. val sc = new SparkContext(conf);
  6. val studentList = Array(
  7. Tuple2(1,"leo"),
  8. Tuple2(2,"jack"),
  9. Tuple2(3,"tom"))
  10. val scoreList = Array(
  11. Tuple2(1,300),
  12. Tuple2(2,432),
  13. Tuple2(3,329));
  14. val students = sc.parallelize(studentList);
  15. val scores = sc.parallelize(scoreList);
  16. val studentScores = students.join(scores);
  17. studentScores.foreach(studentScores => {
  18. println("student id: " + studentScores._1);
  19. println("student name:" + studentScores._2._1);
  20. println("student score:" + studentScores._2._1);
  21. })
  22. }

cogroup案例:打印学生成绩

java 版本

  1. /**
  2. * cogroup案例:打印学生成绩
  3. */
  4. private static void cogroup() {
  5. // 创建SparkConf
  6. SparkConf conf = new SparkConf()
  7. .setAppName("cogroup")
  8. .setMaster("local");
  9. // 创建JavaSparkContext
  10. JavaSparkContext sc = new JavaSparkContext(conf);
  11. // 模拟集合
  12. List<Tuple2<Integer, String>> studentList = Arrays.asList(
  13. new Tuple2<Integer, String>(1, "leo"),
  14. new Tuple2<Integer, String>(2, "jack"),
  15. new Tuple2<Integer, String>(3, "tom"));
  16. List<Tuple2<Integer, Integer>> scoreList = Arrays.asList(
  17. new Tuple2<Integer, Integer>(1, 100),
  18. new Tuple2<Integer, Integer>(2, 90),
  19. new Tuple2<Integer, Integer>(3, 60),
  20. new Tuple2<Integer, Integer>(1, 70),
  21. new Tuple2<Integer, Integer>(2, 80),
  22. new Tuple2<Integer, Integer>(3, 50));
  23. // 并行化两个RDD
  24. JavaPairRDD<Integer, String> students = sc.parallelizePairs(studentList);
  25. JavaPairRDD<Integer, Integer> scores = sc.parallelizePairs(scoreList);
  26. // cogroup与join不同
  27. // 相当于是,一个key join上的所有value,都给放到一个Iterable里面去了
  28. // cogroup,不太好讲解,希望大家通过动手编写我们的案例,仔细体会其中的奥妙
  29. JavaPairRDD<Integer, Tuple2<Iterable<String>, Iterable<Integer>>> studentScores =
  30. students.cogroup(scores);
  31. // 打印studnetScores RDD
  32. studentScores.foreach(
  33. new VoidFunction<Tuple2<Integer,Tuple2<Iterable<String>,Iterable<Integer>>>>() {
  34. private static final long serialVersionUID = 1L;
  35. @Override
  36. public void call(
  37. Tuple2<Integer, Tuple2<Iterable<String>, Iterable<Integer>>> t)
  38. throws Exception {
  39. System.out.println("student id: " + t._1);
  40. System.out.println("student name: " + t._2._1);
  41. System.out.println("student score: " + t._2._2);
  42. System.out.println("===============================");
  43. }
  44. });
  45. // 关闭JavaSparkContext
  46. sc.close();
  47. }

action操作开发实战

reduce
java 版本

  1. private static void reduce() {
  2. // 创建SparkConf和JavaSparkContext
  3. SparkConf conf = new SparkConf()
  4. .setAppName("reduce")
  5. .setMaster("local");
  6. JavaSparkContext sc = new JavaSparkContext(conf);
  7. // 有一个集合,里面有1到10,10个数字,现在要对10个数字进行累加
  8. List<Integer> numberList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
  9. JavaRDD<Integer> numbers = sc.parallelize(numberList);
  10. // 使用reduce操作对集合中的数字进行累加
  11. // reduce操作的原理:
  12. // 首先将第一个和第二个元素,传入call()方法,进行计算,会获取一个结果,比如1 + 2 = 3
  13. // 接着将该结果与下一个元素传入call()方法,进行计算,比如3 + 3 = 6
  14. // 以此类推
  15. // 所以reduce操作的本质,就是聚合,将多个元素聚合成一个元素
  16. int sum = numbers.reduce(new Function2<Integer, Integer, Integer>() {
  17. private static final long serialVersionUID = 1L;
  18. @Override
  19. public Integer call(Integer v1, Integer v2) throws Exception {
  20. return v1 + v2;
  21. }
  22. });
  23. System.out.println(sum);
  24. // 关闭JavaSparkContext
  25. sc.close();
  26. }

Scala版本

  1. def reduce(): Unit = {
  2. val conf = new SparkConf().setAppName("reduce").setMaster("local");
  3. val sc = new SparkContext(conf);
  4. val numberArray = Array(1,2,3,4,5,6,7,8)
  5. val numbers = sc.parallelize(numberArray, 1)
  6. val sum = numbers.reduce(_+_)
  7. println(sum)
  8. }

collect
java 版本

  1. private static void collect() {
  2. // 创建SparkConf和JavaSparkContext
  3. SparkConf conf = new SparkConf()
  4. .setAppName("collect")
  5. .setMaster("local");
  6. JavaSparkContext sc = new JavaSparkContext(conf);
  7. // 有一个集合,里面有1到10,10个数字,现在要对10个数字进行累加
  8. List<Integer> numberList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
  9. JavaRDD<Integer> numbers = sc.parallelize(numberList);
  10. // 使用map操作将集合中所有数字乘以2
  11. JavaRDD<Integer> doubleNumbers = numbers.map(
  12. new Function<Integer, Integer>() {
  13. private static final long serialVersionUID = 1L;
  14. @Override
  15. public Integer call(Integer v1) throws Exception {
  16. return v1 * 2;
  17. }
  18. });
  19. // 不用foreach action操作,在远程集群上遍历rdd中的元素
  20. // 而使用collect操作,将分布在远程集群上的doubleNumbers RDD的数据拉取到本地
  21. // 这种方式,一般不建议使用,因为如果rdd中的数据量比较大的话,比如超过1万条
  22. // 那么性能会比较差,因为要从远程走大量的网络传输,将数据获取到本地
  23. // 此外,除了性能差,还可能在rdd中数据量特别大的情况下,发生oom异常,内存溢出
  24. // 因此,通常,还是推荐使用foreach action操作,来对最终的rdd元素进行处理
  25. List<Integer> doubleNumberList = doubleNumbers.collect();
  26. for(Integer num : doubleNumberList) {
  27. System.out.println(num);
  28. }
  29. // 关闭JavaSparkContext
  30. sc.close();
  31. }

scala版本

  1. def collect(): Unit = {
  2. val conf = new SparkConf().setAppName("collect").setMaster("local");
  3. val sc = new SparkContext(conf);
  4. val numberArray = Array(1,2,3,4,5,6,7,8,9);
  5. val numbers = sc.parallelize(numberArray, 1)
  6. val sum = numbers.reduce(_ + _)
  7. println(sum)
  8. }

count
java 版本

  1. private static void count() {
  2. // 创建SparkConf和JavaSparkContext
  3. SparkConf conf = new SparkConf()
  4. .setAppName("count")
  5. .setMaster("local");
  6. JavaSparkContext sc = new JavaSparkContext(conf);
  7. // 有一个集合,里面有1到10,10个数字,现在要对10个数字进行累加
  8. List<Integer> numberList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
  9. JavaRDD<Integer> numbers = sc.parallelize(numberList);
  10. // 对rdd使用count操作,统计它有多少个元素
  11. long count = numbers.count();
  12. System.out.println(count);
  13. // 关闭JavaSparkContext
  14. sc.close();
  15. }

scala版本

  1. def count(): Unit = {
  2. val conf = new SparkConf().setAppName("count").setMaster("local");
  3. val sc = new SparkContext(conf);
  4. val numberArray = Array(1,2,3,4,5,6,7,8,9);
  5. val numbers = sc.parallelize(numberArray);
  6. val count = numbers.count();
  7. println(count)
  8. }

take
java版本

  1. private static void take() {
  2. // 创建SparkConf和JavaSparkContext
  3. SparkConf conf = new SparkConf()
  4. .setAppName("take")
  5. .setMaster("local");
  6. JavaSparkContext sc = new JavaSparkContext(conf);
  7. // 有一个集合,里面有1到10,10个数字,现在要对10个数字进行累加
  8. List<Integer> numberList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
  9. JavaRDD<Integer> numbers = sc.parallelize(numberList);
  10. // 对rdd使用count操作,统计它有多少个元素
  11. // take操作,与collect类似,也是从远程集群上,获取rdd的数据
  12. // 但是collect是获取rdd的所有数据,take只是获取前n个数据
  13. List<Integer> top3Numbers = numbers.take(3);
  14. for(Integer num : top3Numbers) {
  15. System.out.println(num);
  16. }
  17. // 关闭JavaSparkContext
  18. sc.close();
  19. }

scala 版本

  1. def take(): Unit = {
  2. val conf = new SparkConf().setAppName("take").setMaster("local");
  3. val sc = new SparkContext(conf);
  4. val numberArray = Array(1,2,3,4,5,6,7);
  5. val numbers = sc.parallelize(numberArray);
  6. val top3Number = numbers.take(3);
  7. for(num <- top3Number) {
  8. println(num)
  9. }
  10. }

saveAsTextFile
Java版本

  1. private static void saveAsTextFile() {
  2. // 创建SparkConf和JavaSparkContext
  3. SparkConf conf = new SparkConf()
  4. .setAppName("saveAsTextFile");
  5. JavaSparkContext sc = new JavaSparkContext(conf);
  6. // 有一个集合,里面有1到10,10个数字,现在要对10个数字进行累加
  7. List<Integer> numberList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
  8. JavaRDD<Integer> numbers = sc.parallelize(numberList);
  9. // 使用map操作将集合中所有数字乘以2
  10. JavaRDD<Integer> doubleNumbers = numbers.map(
  11. new Function<Integer, Integer>() {
  12. private static final long serialVersionUID = 1L;
  13. @Override
  14. public Integer call(Integer v1) throws Exception {
  15. return v1 * 2;
  16. }
  17. });
  18. // 直接将rdd中的数据,保存在HFDS文件中
  19. // 但是要注意,我们这里只能指定文件夹,也就是目录
  20. // 那么实际上,会保存为目录中的/double_number.txt/part-00000文件
  21. doubleNumbers.saveAsTextFile("hdfs://spark1:9000/double_number.txt");
  22. // 关闭JavaSparkContext
  23. sc.close();
  24. }

countByKey
java版本

  1. private static void countByKey() {
  2. // 创建SparkConf
  3. SparkConf conf = new SparkConf()
  4. .setAppName("countByKey")
  5. .setMaster("local");
  6. // 创建JavaSparkContext
  7. JavaSparkContext sc = new JavaSparkContext(conf);
  8. // 模拟集合
  9. List<Tuple2<String, String>> scoreList = Arrays.asList(
  10. new Tuple2<String, String>("class1", "leo"),
  11. new Tuple2<String, String>("class2", "jack"),
  12. new Tuple2<String, String>("class1", "marry"),
  13. new Tuple2<String, String>("class2", "tom"),
  14. new Tuple2<String, String>("class2", "david"));
  15. // 并行化集合,创建JavaPairRDD
  16. JavaPairRDD<String, String> students = sc.parallelizePairs(scoreList);
  17. // 对rdd应用countByKey操作,统计每个班级的学生人数,也就是统计每个key对应的元素个数
  18. // 这就是countByKey的作用
  19. // countByKey返回的类型,直接就是Map<String, Object>
  20. Map<String, Object> studentCounts = students.countByKey();
  21. for(Map.Entry<String, Object> studentCount : studentCounts.entrySet()) {
  22. System.out.println(studentCount.getKey() + ": " + studentCount.getValue());
  23. }
  24. // 关闭JavaSparkContext
  25. sc.close();
  26. }

scala版本

  1. def countByKey(): Unit = {
  2. val conf = new SparkConf().setAppName("countByKey").setMaster("local");
  3. val sc = new SparkContext(conf);
  4. val studentList = Array(Tuple2("class1","leo"), Tuple2("class2","tom"), Tuple2("class4", "adbc"));
  5. val students = sc.parallelize(studentList);
  6. val studentCounts = students.countByKey();
  7. println(studentCounts)
  8. }