私たちはレポートを処理した場合、どのように統計的な指標の他の属性の属性次元にします。
以下の場合は、その統計的な指標の様々な寸法に割り当てられた当社の鉄道局に当社の報告であるが、様々な方法を使用することを
達成するためにsparkcoreを使用することで、達成するために使用sparksqlがあり
、次のコードは、sparkcoreを達成するために使用されますの
package report
import java.util.Properties
import com.google.gson.Gson
import config.ConfigHelper
import org.apache.commons.lang.StringUtils
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.{DataFrame, SaveMode, SparkSession}
import scalikejdbc.{DB, SQL}
import scalikejdbc.config.DBs
//根据铁路局维度进行atperror报表统计
object AttachRWBureauAnaylysis {
def main(args: Array[String]): Unit = {
//会有两个参数,一个是输入路径,一个是输出路径,因此参数<2的话说明有参数丢失,报错提醒我们检查
if(args.length<2){
println("参数错误")
return
}
//session
val session = SparkSession
.builder()
//名字
.appName(this.getClass.getName)
//本地的
.master("local[*]")
//配置spark的序列化方式
//spark1.6之前的版本必须得设置
.config("spark.serializer",ConfigHelper.serializer)
.getOrCreate()
//导入隐式转换
import session.implicits._
//读取数据
val sourceFrame: DataFrame = session.read.parquet(args(0))
//处理数据
//row:行
//每一行进行一次处理
val rddResult: RDD[(String, List[Int])] = sourceFrame.map(row => {
//获取铁路局
val attachRWBureau: String = row.getAs[String]("MPacketHead_AttachRWBureau")
//获取atperror
val atpError = row.getAs[String]("MATPBaseInfo_AtpError")
//判断指标
//如果atpError不为空,前面为1,如果atpError为空,那么前面为0
//先判断atpError不为空,如果为空,则执行下面的else语句,全部输出为0
val listAtpError: List[Int] = if (StringUtils.isNotEmpty(atpError)) {
val listError: List[Int] =
if (atpError.equals("车载主机")) {
List[Int](1, 0, 0, 0, 0, 0, 0, 0)
} else if (atpError.equals("无线传输单元")) {
List[Int](0, 1, 0, 0, 0, 0, 0, 0)
} else if (atpError.equals("应答器信息接收单元")) {
List[Int](0, 0, 1, 0, 0, 0, 0, 0)
} else if (atpError.equals("轨道电路信息读取器")) {
List[Int](0, 0, 0, 1, 0, 0, 0, 0)
} else if (atpError.equals("测速测距单元")) {
List[Int](0, 0, 0, 0, 1, 0, 0, 0)
} else if (atpError.equals("人机交互接口单元")) {
List[Int](0, 0, 0, 0, 0, 1, 0, 0)
} else if (atpError.equals("列车接口单元")) {
List[Int](0, 0, 0, 0, 0, 0, 1, 0)
} else if (atpError.equals("司法记录单元")) {
List[Int](0, 0, 0, 0, 0, 0, 0, 1)
} else {
//这是为了防止获取的atpError的值都不符合上述判断条件的情况
List[Int](0, 0, 0, 0, 0, 0, 0, 0)
}
//两个list的拼接要用++
List[Int](1) ++ listError
} else {
//如果atpError为空的情况,说明这行的这个属性没有值,那么全取为0即可
List[Int](0, 0, 0, 0, 0, 0, 0, 0, 0)
}
//创建一个容器用来存放标签
//两个list的拼接要用++
//这个是为了在整合以后统计总共多少条数据用,相当于数量
val list: List[Int] = List[Int](1) ++ listAtpError
//scala中默认最后一行是返回值
//也就是说每一行处理以后返回的都是一个元组
(attachRWBureau, list)
//spark1.6之前操作完之后自动返回的就是rdd
//之所以要转成rdd,是因为只有rdd才有rdduceByKey
}).rdd
//这个就是把数据都聚合起来,也就是把每一行的数据都加起来
.reduceByKey {
//zip函数是把两个list聚合
//开发中,需要聚合的文段
//举个例子:
//RDD中有如下元素
//kv
//((a,b),List(7,8,9))
//((a,b),List(1,2,3))
//((a,b),List(4,5,6))
//((c,d),List(4,5,6))
//。。。。。。
//reducebykey后要对v进行操作
//原理将v中的list前后zip再map每个元素进行逐个元组元素(a,b)的累加。
//a代表v的前一个元素,b代表v的后一个元素
//如val a=List(7,8,9)
//val b=List (1,2,3)
//val k= a zip b =((7,1),(8,2)(9,3))
//k map (tp=>tp._1+tp._2) ----- > (8,10,12)
//如此循环 结果:
//新RDD中的元素:
//((a,b),List(12,15,18))
//((c,d),List(4,5,6))
//。。。。。。
(list1, list2) => list1 zip list2 map (tp => tp._1 + tp._2)
}
//上面已经把数据都聚合好了,接下来就是使用各种不同的方法来输出结果
//这里主要使用的是json方法和jdbc方法,每种方法都用了两种方式来完成
//rddResult就是最后整合好的rdd,因此都在使用rddResult
//因为格式都是(attachRWBureau, list)的元组,所以tp._1的时候说的就是attachRWBureau属性,tp._2的时候就是list
//因为list数组有十个,所以分为0-9
//json方式1 json
// rddResult.map(tp=>(tp._1,tp._2(0),tp._2(1),tp._2(2),tp._2(3),tp._2(4),tp._2(5),tp._2(6),tp._2(7),tp._2(8),tp._2(9)))
//设置列名
// .toDF("AttachRWBureau","allData","atpError","main","wifi","balise","TCR","speed","DMI","TIU","JRU")
//写出数据
// .write.json(args(1))
//json方式2 gson
// rddResult.map(tp=>{
//创建一个Gson对象
// val gson = new Gson()
//调用gson对象中的方法
//写出数据
//使用了下面写的样例类
// gson.toJson(AttachRWBureauKPI(tp._1,tp._2(0),tp._2(1),tp._2(2),tp._2(3),tp._2(4),tp._2(5),tp._2(6),tp._2(7),tp._2(8),tp._2(9)))
// }).saveAsTextFile(args(1))
//mysql中方式1 java的jdbc
// val props=new Properties()
// props.setProperty("driver",ConfigHelper.driver)
// props.setProperty("user",ConfigHelper.user)
// props.setProperty("password",ConfigHelper.password)
// rddResult.map(tp=>(tp._1,tp._2(0),tp._2(1),tp._2(2),tp._2(3),tp._2(4),tp._2(5),tp._2(6),tp._2(7),tp._2(8),tp._2(9)))
//设置列名
// .toDF("AttachRWBureau","allData","atpError","main","wifi","balise","TCR","speed","DMI","TIU","JRU")
//写出数据
//根据配置文件,存在本地的mysql中
// .write.mode(SaveMode.Overwrite)
// .jdbc(ConfigHelper.url,"AttachRWBureauAnaylysis",props)
//mysql中方式2 scalikejdbc
//插入数据
DBs.setup()
rddResult.foreachPartition(partition=>{
DB.localTx{implicit session=>
partition.foreach(tp=>{
SQL("insert into attachrwbureauanaylysis values (?,?,?,?,?,?,?,?,?,?,?)")
.bind(tp._1,tp._2(0),tp._2(1),tp._2(2),tp._2(3),tp._2(4),tp._2(5),tp._2(6),tp._2(7),tp._2(8),tp._2(9))
.update()
.apply()
})
}
})
//释放资源
session.stop()
}
}
//样例类
case class AttachRWBureauKPI(
AttachRWBureau:String,
allData:Int,
atpError:Int,
main:Int,
wifi:Int,
balise:Int,
TCR:Int,
speed:Int,
DMI:Int,
TIU:Int,
JRU:Int
)
以下の方法をsparksqlを使用して実装され
package report
import config.ConfigHelper
import org.apache.spark.sql.SparkSession
//应用sparksql进行铁路局报表统计
object AttachRWBureauAnaylysisSQL {
def main(args: Array[String]): Unit = {
//session
val session=SparkSession
.builder()
//设置是否是在本地运行
//*代表几个线程
.master("local[*]")
//设置进程的名称
.appName(this.getClass.getSimpleName)
//序列化
.config("spark.serializer",ConfigHelper.serializer)
.getOrCreate()
//导入隐式转换
import session.implicits._
//读取数据
val frame = session.read.parquet(args(0))
//注册临时表
frame.createTempView("logs")
//写sql语句
//sql语句嵌套判断,if else
//if elseif else目前不支持这种形式
//想实现多分支 case when else end
//利用udf来写
//注册一个udf
session.udf.register("myif",(boolean:Boolean)=>if(boolean) 1 else 0)
session.sql(
"""
|select
| MPacketHead_AttachRWBureau,
| count(*) as allData,
| sum(if(MATPBaseInfo_AtpError!=null and MATPBaseInfo_AtpError!='',1,0)) as atperror,
| sum(case when MATPBaseInfo_AtpError = '车载主机' then 1 when MATPBaseInfo_AtpError='' then 0.5 else 0 end) as main,
| sum(myif(MATPBaseInfo_AtpError = '无线传输单元')) as wifi,
| sum(if(MATPBaseInfo_AtpError = '应答器信息接收单元',1,0)) as balise,
| sum(if(MATPBaseInfo_AtpError = '轨道电路信息读取器',1,0)) as TCR,
| sum(if(MATPBaseInfo_AtpError = '测速测距单元',1,0)) as speed,
| sum(if(MATPBaseInfo_AtpError = '人机交互接口单元',1,0)) as DMI,
| sum(if(MATPBaseInfo_AtpError = '列车接口单元',1,0)) as TIU,
| sum(if(MATPBaseInfo_AtpError = '司法记录单元',1,0)) as JRU
|from logs
|group by MPacketHead_AttachRWBureau
""".stripMargin).show()
//释放资源
session.stop()
}
}
コンフィギュレーションファイル
application.conf
#配置文件
#配置压缩格式
parquet.code="snappy"
#配置序列化方式
spark.serializer="org.apache.spark.serializer.KryoSerializer"
#配置jdbc链接
jdbc.url="jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8"
jdbc.driver="com.mysql.jdbc.Driver"
jdbc.user="root"
jdbc.password="000000"
#配置scalikejdbc链接
db.default.url="jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8"
db.default.driver="com.mysql.jdbc.Driver"
db.default.user="root"
db.default.password="000000"
ConfigHelper.scala
package config
import com.typesafe.config.{Config, ConfigFactory}
object ConfigHelper {
//加载配置文件
private lazy val load: Config = ConfigFactory.load()
//加载压缩格式
val parquetCode: String = load.getString("parquet.code")
//加载序列化方式
val serializer: String = load.getString("spark.serializer")
//加载jdbc
val url: String = load.getString("jdbc.url")
val driver: String = load.getString("jdbc.driver")
val user: String = load.getString("jdbc.user")
val password: String = load.getString("jdbc.password")
//加载scalikejdbc
val url2: String = load.getString("db.default.url")
val driver2: String = load.getString("db.default.driver")
val user2: String = load.getString("db.default.user")
val password2: String = load.getString("db.default.password")
}