发现一个idea很神奇的功能,每次写一堆算子的时候,先在最后面写一个Action算子过去,然后再从中间开始写transformation算子,这个时候神奇的事情发生了,在每个算子后面会显示出灰色的返回值类型!!!
文章目录
一、数据背景
该数据每日进行采集汇总。数据范围涵盖全国主要省份(港澳台、西藏、海南暂无数据)的180+的大型农产品批发市场,380+的农产品品类(由于季节性和地域性等特点,每日的数据中不一定会涵盖全部的农产品品类)。
二、数据类型
农产品批发市场价格数据products.txt
中文名称 英文名称 数据类型
农产品名称(列1) name string
批发价格(列2) price float
采集时间(列3) craw_time timestamp
批发市场名称(列4) market string
省份(列5) province string
城市(列6) city string
三、功能要求
要求使用分别使用RDD、DataFrame两种方式实现
1、农产品市场个数统计
(省份,蔬菜,1)
1)统计每个省份的农产品市场总数
2)统计没有农产品市场的省份有哪些
2、农产品种类统计
1)根据农产品类型数量,统计排名前 3 名的省份
2)根据农产品类型数量,统计每个省份排名前 3 名的农产品市场
3、价格区间统计,计算山西省每种农产品的价格波动趋势,即计算每天价格均值,并将结果输出到控制台上。
某种农产品的价格均值计算公式:
PAVG = (PM1+PM2+…+PMn-max§-min§)/(N-2)
其中,P 表示价格,Mn 表示 market,即农产品市场。PM1 表示 M1 农产品市场的该产品价格,max§表示价格最大值,min§价格最小值。
四、SparkCore代码实现
4.1 农产品市场个数统计
4.1.1
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
/**
* 1)统计每个省份的农产品市场总数
*/
object ByRdd_1_1 {
private val sc: SparkContext = new SparkContext(new SparkConf().setMaster("local").setAppName("dataframe"))
private val productRDD: RDD[String] = sc.textFile("src/file/test/products.txt")
def main(args: Array[String]): Unit = {
//1.按照一个或者多个tab键切割(\s匹配任何空白字符,包括空格、制表符、换页符等等)
val provinceRDD: RDD[(String, String)] = productRDD.filter(_.split("\\s+").length == 6)
.map(line => {
val parts: Array[String] = line.split("\\s+")
(parts(4), parts(3))
})
//2.去除重复数据,按照key分组计算
val result: collection.Map[String, Long] = provinceRDD.distinct()
.countByKey()
for ((k, v) <- result) {
println(s"省份:$k ,数量:$v")
}
}
}
4.1.2
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.rdd.RDD
/**
* 2)统计没有农产品市场的省份有哪些
*/
object ByRDD_1_2 {
private val sc: SparkContext = new SparkContext(new SparkConf().setMaster("local").setAppName("dataframe"))
private val productRDD: RDD[String] = sc.textFile("src/file/test/products.txt")
private val allProvinceRDD: RDD[String] = sc.textFile("src/file/test/allprovinces.txt")
def main(args: Array[String]): Unit = {
//1.按照一个或者多个tab键切割(\s匹配任何空白字符,包括空格、制表符、换页符等等)
val province: RDD[String] = productRDD.filter(_.split("\\s+").length == 6)
.map(line => line.split("\\s+")(4))
//2.读取省份信息
val allProvinces: RDD[String] = allProvinceRDD.map(line => line.split("\\s+")(0))
//3.求出省份
val result: RDD[String] = allProvinces.subtract(province)
result.foreach(println)
}
}
4.2农产品种类统计
4.2.1
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
/**
*2、农产品种类统计
*1)根据农产品类型数量,统计排名前 3 名的省份
*/
object ByRDD_2_1 {
private val sc: SparkContext = new SparkContext(new SparkConf().setMaster("local").setAppName("dataframe"))
private val productRDD: RDD[String] = sc.textFile("src/file/test/products.txt")
def main(args: Array[String]): Unit = {
//1.得到RDD[(省份, 种类)]
val provinceAndType: RDD[(String, String)] = productRDD.filter(_.split("\\s+").length == 6)
.map(line => {
val parts: Array[String] = line.split("\\s+")
(parts(4), parts(0))
})
//2.计算每个省份的种类和
val sumRDD: RDD[(String, Int)] = provinceAndType.distinct().mapValues(_ => 1).reduceByKey(_ + _)
sumRDD.sortBy(-_._2)
.take(3)
.foreach(println)
}
}
4.2.2
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.rdd.RDD
object ByRDD_3_1 {
private val sc: SparkContext = new SparkContext(new SparkConf().setMaster("local").setAppName("dataframe"))
private val productRDD: RDD[String] = sc.textFile("src/file/test/products.txt")
def main(args: Array[String]): Unit = {
//1.获取 RDD[((省份, 市场), 种类)]
val provinceAndTypeRDD: RDD[((String, String), String)] = productRDD.filter(_.split("\\s+").length == 6)
.map(line => {
val parts: Array[String] = line.split("\\s+")
((parts(4), parts(3)),parts(0))
})
provinceAndTypeRDD.distinct()
.mapValues(_ => 1) //这一步可以在1.位置做
.reduceByKey(_ + _)
.map(t => (t._1._1, (t._1._2, t._2))) //重新划分Rdd的类型
.groupByKey()
.mapValues(_.toList.sortBy(-_._2).take(3))
.mapValues(_.map(_._1)) //去除数量,保留省份
.foreach(println)
}
}
4.3计算山西省每种农产品的价格波动趋势
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.rdd.RDD
object ByRDD_3_2 {
private val sc: SparkContext = new SparkContext(new SparkConf().setMaster("local").setAppName("dataframe"))
private val productRDD: RDD[String] = sc.textFile("src/file/test/products.txt")
def main(args: Array[String]): Unit = {
// RDD[(农产品, 价格)
val nameAndPriceRDD: RDD[(String, Double)] = productRDD.filter(_.split("\\s+").length == 6)
.map(line => {
val productInfo: Array[String] = line.split("\\s+")
(productInfo(4), productInfo(0), productInfo(1).toDouble)
})
.filter(_._1.equals("山西"))
.map(t => (t._2, t._3))
nameAndPriceRDD
.groupByKey()
.map(t => {
if (t._2.size>2)
(t._1, ((t._2.sum - t._2.max - t._2.min)/t._2.size).formatted("%.2f"))
else
(t._1, (t._2.sum/t._2.size).formatted("%.2f"))
}) // 农产品分类
.foreach(println)
}
}
五、SparkSQL代码实现
import exam03.common._
import org.apache.spark.sql.{DataFrame, Dataset, Row, SparkSession}
/**
*
* 1、农产品市场个数统计
* 1)统计每个省份的农产品市场总数
* 2)统计没有农产品市场的省份有哪些
* 2、农产品种类统计
* 1)根据农产品类型数量,统计排名前 3 名的省份
* 2)根据农产品类型数量,统计每个省份排名前 3 名的农产品市场
* 3、价格区间统计,计算山西省每种农产品的价格波动趋势,即计算每天价格均值,并将结果输出到控制台上。
*
*/
object MainApplication extends App {
// 1. 获取SparkSession
private val spark: SparkSession = SparkHelper.getSparkSession
import spark.implicits._
import org.apache.spark.sql.functions._
// 2. 创建DF
private val productsDF: DataFrame = {
spark.read.option("delimiter", "\t").csv(Constants.PATH_PRODUCTS)
.withColumnRenamed("_c0", "name")
.withColumnRenamed("_c1", "price")
.withColumnRenamed("_c2", "craw_time")
.withColumnRenamed("_c3", "market")
.withColumnRenamed("_c4", "province")
.withColumnRenamed("_c5", "city")
.na.drop() // drop掉null值
}
private val provincesDF: DataFrame = {
spark.read.option("delimiter", "\t").csv(Constants.PATH_PROVINCES)
.withColumnRenamed("_c0", "province")
.withColumnRenamed("_c1", "short_hand")
.na.drop()
}
// 3. 题目实现
// 3.1. 统计每个省份的农产品市场总数
productsDF.select("market", "province").distinct().groupBy("province").count().show()
// 3.2. 统计没有农产品市场的省份有哪些
private val existsProvinceDF: Dataset[Row] = productsDF.select("province", "market").distinct()
private val allProvinceDF: Dataset[Row] = provincesDF.select("province").distinct()
existsProvinceDF.join(allProvinceDF, Seq("province"), "right")
.filter("market is null")
.drop("market")
.show()
// 3.3. 根据农产品类型数量,统计排名前 3 名的省份
productsDF.select("name", "province")
.groupBy("province")
.agg(countDistinct("name").as("count"))
.orderBy(-'count)
.limit(3)
.show()
// 3.4. 根据农产品类型数量,统计每个省份排名前 3 名的农产品市场
productsDF.select("name","market","province")
.groupBy("province","market").count()
.orderBy($"province",$"count".desc)
.repartition(provincesDF.count.asInstanceOf[Int],$"province")
.foreachPartition(it=>{it.take(3).foreach(println)})
// 3.5. 计算山西省的每种农产品的价格波动趋势,即计算每天价格均值
productsDF.filter("province='山西'")
.groupBy("craw_time","name")
.agg(when(count($"price")>2,((sum($"price")-max($"price")-min($"price"))/(count($"price")-2)))
.otherwise(sum($"price")/count($"price"))
.as("pavg"))
.selectExpr("craw_time","name","cast(pavg as decimal(20,2)) as pavg")
.show()
}
六、业务数据
products.txt
茄子 3.20 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
西红柿 4.20 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
黄瓜 4.00 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
冬瓜 2.20 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
白萝卜 1.40 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
胡萝卜 1.60 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
生姜 12.00 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
豆角 6.00 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
香蕉 6.00 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
猪肉 21.00 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
鸡蛋 8.00 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
土豆 2.00 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
菜花 3.20 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
洋白菜 2.00 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
大蒜 3.80 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
生菜 5.00 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
西葫芦 3.20 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
西瓜 5.80 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
活鲤鱼 12.00 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
茴香 4.00 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
香菇 8.00 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
菠菜 3.00 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
小葱 1.40 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
富士苹果 6.00 2018/1/1 河北怀来县就西果菜批发市场有限责任公司 河北 怀来
活草鱼 14.00 2018/1/1 江苏建湖县水产批发市场 江苏 建湖
活鲫鱼 14.00 2018/1/1 江苏建湖县水产批发市场 江苏 建湖
黑鱼 20.00 2018/1/1 江苏建湖县水产批发市场 江苏 建湖
花鲢活鱼 12.00 2018/1/1 江苏建湖县水产批发市场 江苏 建湖
白鲢活鱼 8.00 2018/1/1 江苏建湖县水产批发市场 江苏 建湖
野生甲鱼 420.00 2018/1/1 江苏建湖县水产批发市场 江苏 建湖
人工甲鱼 160.00 2018/1/1 江苏建湖县水产批发市场 江苏 建湖
江蟹 180.00 2018/1/1 江苏建湖县水产批发市场 江苏 建湖
大白菜 0.70 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
洋白菜 2.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
韭菜 3.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
芹菜 2.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
菠菜 3.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
油菜 1.20 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
菜花 3.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
蒜苔 8.60 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
生菜 5.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
黄瓜 3.40 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
豆角 7.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
长茄子 2.80 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
尖椒 5.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
青椒 4.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
西红柿 3.60 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
良薯 3.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
红萝卜 1.20 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
白萝卜 1.60 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
冬瓜 1.10 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
南瓜 6.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
莴笋 4.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
西葫芦 3.20 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
葱头 1.40 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
莲藕 3.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
大葱 3.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
平菇 4.60 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
香菇 7.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
苹果 8.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
香蕉 6.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
西瓜 2.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
巨峰葡萄 8.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
猪肉 21.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
牛肉 48.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
羊肉 46.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
鸡蛋 9.60 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
白条鸡 17.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
活草鱼 14.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
活鲤鱼 10.50 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
白鲢活鱼 16.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
花鲢活鱼 14.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
活鲫鱼 13.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
大带鱼 19.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
大黄花鱼 25.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
粳米 4.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
面粉 2.90 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
菜油 12.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
豆油 10.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
花生油 16.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
香油 30.00 2018/1/1 山西大同振华蔬菜批发市场 山西 大同
大白菜 0.90 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
生菜 2.20 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
大葱 2.80 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
小葱 3.00 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
大蒜 4.20 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
鱼腥草(折耳根) 4.40 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
尖椒 7.60 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
黄瓜 3.20 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
冬瓜 1.10 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
南瓜 2.20 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
白萝卜 1.00 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
胡萝卜 2.60 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
土豆 2.00 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
生姜 9.00 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
莲藕 5.20 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
富士苹果 6.00 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
香蕉 3.00 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
猪肉 23.00 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
洋白菜 1.20 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
豌豆 5.20 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
蒜苔 6.80 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
西红柿 4.00 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
条形辣椒干(小米椒) 22.00 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
莴笋 1.40 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
菜花 2.60 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
芹菜 3.00 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
青椒 5.40 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
茄子 4.20 2018/1/1 四川西昌广平农副土特产品市场 四川 西昌
大白菜 1.00 2018/1/1 浙江义乌农贸城 浙江 义乌
芹菜 2.60 2018/1/1 浙江义乌农贸城 浙江 义乌
菠菜 3.60 2018/1/1 浙江义乌农贸城 浙江 义乌
大葱 3.20 2018/1/1 浙江义乌农贸城 浙江 义乌
allprovince.txt
河北 HE
山西 SX
辽宁 LN
吉林 JL
黑龙江 HL
江苏 JS
浙江 ZJ
安徽 AH
福建 FJ
江西 JX
山东 SD
河南 HA
湖北 HB
湖南 HN
广东 GD
海南 HI
四川 SC
贵州 GZ
云南 YN
陕西 SN
甘肃 GS
青海 QH
台湾 TW
内蒙古 IM
广西 GX
西藏 XZ
宁夏 NX
新疆 XJ
香港 HK
澳门 MO
天津 TJ
北京 BJ
重庆 CQ
上海 SH