1、定义类型
在日志解析前我们需要先知道我们需要从日志中获取什么,首先我们要了解一下日志:
这个日志中一共有四个字段分别为:日期、网址、流量、Ip。接下来我们需要再看需求:
需求一:统计imooc主站最受欢迎课程/手记的topn访问次数
需求二:按地市统计imooc主站最受欢迎topn课程
需求三:按流量统计imooc主站最受欢迎的topn课程
从需求上我们可以发现,我们需要什么字段如下:
URL(网址)
CmsType(课程类型)
CmsId(课程Id)
traffic(流量)
ip (ip地址)
city (城市)
time (日期)
day (天)
2、RDD转化为DataFrame
import org.apache.spark.sql.SparkSession
/**
* 使用Spark完成数据清洗操作
*/
object SparkStatCleanJob {
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder().appName("SparkStatCleanJob").master("local[2]").getOrCreate()
//加载文件
val accessRDD = spark.sparkContext.textFile("file:///D:/test/access.log")
//RDD 转 DF
val accessDF = spark.createDataFrame(accessRDD.map(x => AccessConvertUtil.parseLog(x)),AccessConvertUtil.struct)
accessDF.printSchema()
accessDF.show(false)
spark.close()
}
}
package com.kinglone.log
import org.apache.spark.sql.Row
import org.apache.spark.sql.types.{LongType, StringType, StructField, StructType}
/**
* 访问日志转换(输入==>输出)工具类
*/
object AccessConvertUtil {
//定义输出的字段
val struct = StructType(
Array(StructField("url",StringType),
StructField("cmsType",StringType),
StructField("cmsId",LongType),
StructField("traffic",LongType),
StructField("ip",StringType),
StructField("city",StringType),
StructField("time",StringType),
StructField("day",StringType)
)
)
/**
* 根据输入的每一行信息转换成输出的样式
* @param log 输入的每一行记录信息
*/
def parseLog(log:String) = {
try{
val splits = log.split("\t")
val url = splits(1)
val traffic = splits(2).toLong
val ip = splits(3)
val domain = "http://www.imooc.com/"
val cms = url.substring(url.indexOf(domain) + domain.length)
val cmsTypeId = cms.split("/")
var cmsType = ""
var cmsId = 0l
if(cmsTypeId.length > 1) {
cmsType = cmsTypeId(0)
cmsId = cmsTypeId(1).toLong
}
// val city = IpUtils.getCity(ip)
val city = ""
val time = splits(0)
val day = time.substring(0,10).replaceAll("-","")
//这个row里面的字段要和struct中的字段对应上
Row(url, cmsType, cmsId, traffic, ip, city, time, day)
} catch {
case e:Exception => Row(0)
}
}
}
输出结果: