目录
将一个 RDD 中的 JSON 数据转换为对象,并进行了一些数据清洗操作。
运用split()以 \ 分割字符,在dateSplit(0) 和dateSplit(1) 用 _ 分开。
统计 每个气象站每年每月记录的降水量总数和没有发生降水的天数:
前 言
Spark:
Spark是一种快速、通用的大数据处理和分析引擎。它最初由加州大学伯克利分校开发,是一个开源项目,旨在提供一种高性能、易于使用的工具,用于处理大规模数据处理和分析工作负载。
Spark支持多种编程语言,包括Scala、Java、Python和R,这使得开发人员可以使用自己熟悉的编程语言来进行大规模数据处理和分析任务。
Spark的一个主要特点是其快速性能。它充分利用内存计算,将数据保存在内存中,以避免磁盘读写的瓶颈,从而显著加快处理速度。Spark还使用了弹性分布式数据集(RDD)这一抽象概念,可以在不同节点上并行处理数据,进一步提高了处理性能。
除了大规模数据处理和分析,Spark还提供了一些高级功能,如流式处理、机器学习和图处理等,使其成为一个强大而全面的大数据处理和分析平台。
Scala:
Scala也是一种函数式语言,其函数也能当成值来使用。Scala提供了轻量级的语法用以定义匿名函数,支持高阶函数,允许嵌套多层函数,并支持柯里化。Scala的case class及其内置的模式匹配相当于函数式编程语言中常用的代数类型。
更进一步,程序员可以利用Scala的模式匹配,编写类似正则表达式的代码处理XML数据。
数据准备:
数据框架的搭建:
package com.cjy.weather
class Weathers(var date: String, //日期
var location: String, //气象站名称
var minTemp: String, //最低温度
var maxTemp: String, //最高温度
var rainfall: String, //当天记录的降雨量(毫米)
var windGustDir: String, //24小时至午夜期间最强阵风的方向
var windGustSpeed: String, //到午夜24小时内最强阵风的速度(km \/ h)
var windDir9am: String, //上午9点的风向
var windDir3pm: String, //下午3点的风向
var windSpeed9am: String, //下午9点前十分钟的平均风速
var windSpeed3pm: String, //下午3点前十分钟的平均风速
var humidity9am: String, //上午9点的湿度(百分比)
var humidity3pm: String, //下午3点的湿度(百分比)
var pressure9am: String, //上午9点时大气压(hpa)降低至平均海平面
var pressure3pm: String, //下午3点时大气压(hpa)降低至平均海平面
var cloud3pm: String, //下午3点,云层遮盖了天空的比例。 以“ oktas”为单位,该单位是高度的单位.
var temp9am: String, //上午9点的温度(摄氏度)
var temp3pm: String, //下午3点的温度(摄氏度)
var rainToday: String, //如果24小时至上午9点的降水量(mm)超过1mm,则为YES,否则为NO
var rainTomorrow: String //第二天的雨量,以毫米为单位。一种衡量“风险”的方法。第二天降雨则YES,否则为NO
)extends Serializable{
}
将一个 RDD 中的 JSON 数据转换为对象,并进行了一些数据清洗操作。
var dateRdd = rdd.map(it=> new Gson().fromJson(it,classOf[Weathers]))
.filter(weather=> !weather.rainfall.equals("NA"))
.map(weather => ((weather.location,conversion(weather.date)),weather.rainfall.toDouble))
这段代码通过使用 reduceByKey
方法对 dateRdd
中的数据进行聚合,计算同一位置和日期的下雨量之和。reduceByKey
方法是基于键(即位置和日期的元组)进行聚合操作的,它将具有相同键的元素进行合并,并且对键值对应的值应用一个指定的聚合函数。
var rainfallSum = dateRdd.reduceByKey((a,b)=>a+b)
首先,使用 filter
方法对 dateRdd
进行过滤,筛选出下雨量为零的数据。_._2
表示元组的第二个元素,即下雨量。_._2 == 0
则表示下雨量等于零的数据。接下来,使用 mapValues
方法将过滤出来的数据转换为键值对,并且将每个键对应的值设为 1。这里使用了占位符 _
表示不关心元组的第一个元素(位置和日期),只对值进行操作。最后,使用 reduceByKey
方法对相同的键进行聚合操作,计算键值对应的值之和。聚合函数仍然是 (a, b) => a + b
,将相同键的值相加。
var zeroSum = dateRdd.filter(_._2 == 0)
.mapValues(_ => 1)
.reduceByKey((a,b)=>a+b)
打印出气象站、年月为、 降水总量为
var df = new DecimalFormat("#.##")
rainfallSum.sortByKey().collect().foreach(it => println("气象站为:" + it._1._1 + " 年月为:" + it._1._2 + " 降水总量为:" + df.format(it._2)))
zeroSum.sortByKey().collect().foreach(it => println("气象站为:" + it._1._1 + " 年月为:" + it._1._2 + " 没有降水的天数为:" + df.format(it._2)))
sparkContext.stop()
运用split()以 \ 分割字符,在dateSplit(0) 和dateSplit(1) 用 _ 分开。
def conversion(date: String): String = {
val dateSplit = date.split("/")
dateSplit(0)+"_"+dateSplit(1)
}
}
统计 每个气象站每年每月记录的降水量总数和没有发生降水的天数:
package com.cjy.rainfallSum
import com.cjy.weather.Weathers
import com.google.gson.Gson
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
import java.text.DecimalFormat
/*
统计 每个气象站每年每月记录的降水量总数和没有发生降水的天数
*/
object RainfallSumAndZeroSum {
def main(args: Array[String]): Unit = {
val sparkConf = new SparkConf().setAppName(RainfallSumAndZeroSum.getClass.getName).setMaster("local[*]")
val sparkContext = new SparkContext(sparkConf)
var rdd:RDD[String] = sparkContext.textFile("hdfs://20210322094--master:9000/Australia.json")
var dateRdd = rdd.map(it=> new Gson().fromJson(it,classOf[Weathers]))
.filter(weather=> !weather.rainfall.equals("NA"))
.map(weather => ((weather.location,conversion(weather.date)),weather.rainfall.toDouble))
var rainfallSum = dateRdd.reduceByKey((a,b)=>a+b)
var zeroSum = dateRdd.filter(_._2 == 0)
.mapValues(_ => 1)
.reduceByKey((a,b)=>a+b)
var df = new DecimalFormat("#.##")
rainfallSum.sortByKey().collect().foreach(it=>println("气象站为:"+it._1._1+" 年月为:"+it._1._2+" 降水总量为:"+df.format(it._2)))
zeroSum.sortByKey().collect().foreach(it=>println("气象站为:"+it._1._1+" 年月为:"+it._1._2+" 没有降水的天数为:"+df.format(it._2)))
sparkContext.stop()
}
def conversion(date: String): String = {
val dateSplit = date.split("/")
dateSplit(0)+"_"+dateSplit(1)
}
}
总结:
从Spark的上手到最后的项目,整个过程我一路磕磕绊绊的时常遇到一些奇怪的问题,还好很多问题都能在百度中解决(遇事不决,可问度娘!)
Spark最突出的表现在于它能将作业与作业之间产生的大规模数据集存储在内存中,spark的应用、算子、Scala语言的学习等等很多很多,我也仅仅刚入门,只能说继续努力吧。
Hadoop MapReduce只能进行离线海量数据的分析,且性能较差,作为后起之秀的Spark性能好,支持的场景多,在企业应用也多,完全可以替代MapReduce。
最后的最后,感谢老师的耐心教导。