数据格式
原格式
日期 | 时间 | 种类 | 监测站1数据 | 监测站…数据 |
---|---|---|---|---|
String | Int | String | Double | Double |
数据清洗
PM2.5表、O3表…
时间 | 监测站 | 数据 |
---|---|---|
String(“yyyy-MM-dd-HH“) | String | Double |
这样会出现大量数据冗余但是去掉了空值,并且以时间和监测站为主键更加容易操作。
源数据表节选:
date | hour | type | 1001A | 1002A |
---|---|---|---|---|
20150102 | 1 | AQI | 117 | 85 |
20150102 | 1 | PM2.5 | 88 | 34 |
20150102 | 1 | PM2.5_24h | 48 | 54 |
思路
先把第一行的表头提取出来,影响操作数据。
除去第一行表头,获取所有数据,对每行数据进行切分,把type作为RDD的主键,再以date+hour作为key,其余数据作为value拼接成map,map为RDD的值。为了区分map中的key和value,date和hour使用",“链接,多个value使用”-"链接。
既(PM2.5,(20150102,1,88-34))
使用filter只取某一个type的数据,然后去掉key,既(20150102,1,88-34)
对RDD进行行转列,对后排的数据进行切分,切分后格式为(20150102,1,Array[88,34])
然后再进行模式匹配,对切分后的数组进行拆分,既行转列(20150102,1,88),(20150102,1,34)
在表头中取出所有的监测站代码组成一个字符串数组
将每一列的数据和监测站代码一一对应。(20150102,1,1001A,88)
输出至文件中。
这个垃圾数据我日,大体上没有问题,具体的文件中全是报错,一定要把所有情况考虑清楚。
有的文件中最后几行没有任何数据,比如22点以后不进行检测的。这样你如果直接去拉去line(3),就会因为没有数据导致数组溢出。
有的文件表头不全,你明明切出来是1563个监测站,但是第1563个监测站就会报数组溢出,挺离谱的。
有的文件甚至连检测的污染物类型都没有,你一取line(2)数组溢出我是没想到的,日了狗了。
数据结构优化
日期 | 监测站 | 0时数据 | 1时数据 | …时数据 |
---|---|---|---|---|
String(“yyyy-MM-dd“) | String | Double | Double | Double |
减少了数据冗余,有效的减少存储量。因为一天一共就24个小时,合并成列也不算多。源数据两千八百多个列就挺尼玛离谱。
这样需要先进行行转列,把表头的监测站代码放进数据中,再列转行,把时间调整到表头,比较麻烦,但是既解决了空值问题,又减少了数据冗余。
既然第一步已经将数据格式化了,就可以存入hive进行操作了。
数据上传
先使用rz命令将数据上传到集群中,再上传至hdfs
hadoop fs -put air2015-2018/ /air/input
数据操作
package com.digitalchina
import java.io.IOException
import org.apache.spark.rdd.RDD
import org.apache.spark.{
SparkConf, SparkContext}
object AirQualityTest {
def main(args: Array[String]): Unit = {
val sparkConf = new SparkConf()
.setAppName("AirQuality")
val sc = new SparkContext(sparkConf)
val readRDD = sc.textFile(args(0))
val airRDD = readRDD.map(
line => {
//分割字符串
val lines = line.split(",")
//先判断到底是否有数据
if(lines.length>3) {
//以日期,时间为key
val key = lines(0) + "," + lines(1)
//剩下的所有数据为value,循环组成一个map
var value = lines(3)
for (i <- 4 to lines.length - 1) {
value = value + "-" + lines(i)
}
//以污染物为主键,map为值组成RDD
(lines(2), (key, value))
}else{
//如果没有数据,就直接给三个空字符串,后面会去掉空字符串,键值不要给污染物类型line(2)
//有的数据没有污染物的类型,尼玛离谱line(2)报了个数组溢出,表结构都没有为什么不丢弃啊?
("", ("", ""))
}
})
collectRDD(airRDD,"PM2.5",a