一、例题
每个输入支件表示班级学生某个学科的成绩,每行内容由两个字段组成,第一个是学生名字,第二个是学生的成绩;编写Spark独立应用程序求出所有学生的平均成绩,并输出到一个新支件中。
下面是输入支件和输出文件的一个样例,供参考。
Algorimm 成绩:
小明 92
小红 87
小新 82
小丽 90
Database成绩:
小明95
小红81
小新89
小丽85
Python成绩:
小明82
小红83
小新94
小丽91
平均成绩如下:
(小红,83.67)
(小新,88.33)
(小明,89.67)
(小丽,88.67)
二、代码
import org.apache.commons.math3.util.Precision.round
import org.apache.spark.{SparkConf, SparkContext}
object Average {
def main(args: Array[String]): Unit = {
//1、创建SparkConf对象,该对象初始化一些数据,如该scala代码程序的名字,连接到主节点master的url地址
val sparkConf = new SparkConf().setMaster("local").setAppName("WordCount")
//2、创建SparkContext对象,该对象时应用程序提交到spark进行计算运行的唯一入口
val sc = new SparkContext(sparkConf)
//通过textFile函数获取数据,同时把数据分割为一行一行,每个数据节点存储一定行数的数据,lines-RDD就是代表这些行的的名字
val Algorimm = sc.textFile("D://scala-spark-rdd/data/Algorimm.txt")
val DataBase = sc.textFile("D://scala-spark-rdd/data/DataBase.txt")
val Python = sc.textFile("D://scala-spark-rdd/data/Python.txt")
//第一步:合并文件
val allGradeAverage = Algorimm.union(DataBase).union(Python)
//map(x => (x.split(" ")(0),x.split(" ")(1))) 作用是把rdd中的每一行以空格分隔,且存放形式为数组,就可以使用下标来访问每行的每一个数据了,这里获取(0)(1)两个数据,组成整体数组形式
val stuArrayKeyValue = allGradeAverage.map(x => (x.split(" ")(0),x.split(" ")(1).toDouble)).mapValues(x => (x,1))
//使用reduceByKey把相同的key即学生名字,的成绩相加,在统计有多少个相同名字的成绩
val totalGrade = stuArrayKeyValue.reduceByKey((x,y) => (x._1+y._1,x._2+y._2))
//总成绩 除以 学科数 = 平均分 round(数值,保留位数)函数是保留指定位数的功能
val averageGrade = totalGrade.mapValues(x => round(x._1.toDouble/x._2.toDouble,2)).foreach(println)
sc.stop()
}
}