guid01,2018-02-28 guid01,2018-03-01 guid01,2018-03-02 guid01,2018-03-04 guid01,2018-03-05 guid01,2018-03-06 guid01,2018-03-07 guid02,2018-03-01 guid02,2018-03-02 guid02,2018-03-03 guid02,2018-03-06
//第一个参数就传true或false因为以后有可能在本地执行,有可能提交到集群里面
val islocal = args(0).toBoolean
//这个主要作用是获取对象
val conf = new SparkConf().setAppName(this.getClass.getCanonicalName)
//通过if判断是local模式运行吗
if(islocal){ //判断是否是本地运行模式,如果是则走本地运行
conf.setMaster("local[*]")
}
//以后指定从哪里读取数据创建RDD
val sc: SparkContext = new SparkContext(conf)
//以后指定从哪里读取数据创建RDD,以后通过参数把他传进来
val lines: RDD[String] = sc.textFile(args(1))
//对数据进行整理
val uidAndDate: RDD[(String, String)] = lines.map(line => {
val fields = line.split(",") //先用逗号切分
val uid = fields(0) //把Uid存到 0 号区
val date = fields(1) //存到1号区
(uid, date) //然后把uid和date放到一起
})
//根据uid进行分组,将同一个用户的登录数据搞到同一个组内
//注意对于k-v类型调用groupByKey最好
val grouped: RDD[(String, Iterable[String])] = uidAndDate.groupByKey()
//在组内的value值进行排序
val uidAndDateDiff: RDD[(String, (String, String))] = grouped.flatMapValues(it => { //把value压平,再把key合在一起
//将迭代器中的数据toList/toSet ,由于可能会出现某个用户每一天会多次登录,所以必须要先对日期去重,然后再转成列表
//在对列表进行排序
val sorted: List[String] = it.toSet.toList.sorted
//定义一个日期类工具,表示可以对日期进行操作
val calendar = Calendar.getInstance()
//创建个日期形式
val sdf: SimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd")
var index = 0
sorted.map(dateStr => {
val date: Date = sdf.parse(dateStr) //转成sdf定义的日期格式,本来是日期格式然后转换成date格式
calendar.setTime(date) //启动修改时间的机制
calendar.add(Calendar.DATE, -index)
index += 1
//dateStr是指原来的时间,第二个参数是把当前时间拿出来
(dateStr, sdf.format(calendar.getTime))
})
})
/* val res: Array[(String, (String, String))] = uidAndDateDiff.collect()
println(res.toBuffer)
sc.stop()*/
//(guid01,(2018-03-04,2018-03-01))
val result1: RDD[((String, String), Iterable[String])] = uidAndDateDiff.map(t => {
//参数1 key值,也就是uid t._2._2 表示被减去之后的日期,
((t._1, t._2._2), t._2._1) //表示登录的日期
//按照key进行分组,查看组内有几条数据
}).groupByKey()
//对value进行操作
val result2: RDD[(String, Int, String, String)] = result1.mapValues(it => {
val list: List[String] = it.toList
val times = list.size
//怎样才能拿出一个起始时间,和一个结束时间呢
val beginTime: String = list.head
val endTime: String = list.last
(times, beginTime, endTime)
}).map(t => {
//用户ID,连续多少天,起始时间,结束时间,
(t._1._1, t._2._1, t._2._2, t._2._3)
})
println(result2.collect().toBuffer)
sc.stop()
//第一个参数传入true或false,因为后面肯能会在本地或者集群中运行
val isLocal: Boolean = args(0).toBoolean
//这个主要作用是获取对象
val conf: SparkConf = new SparkConf().setAppName(this.getClass.getCanonicalName)
//通过if判断是否在本地运行,一般在做测试的时候,是在本地运行
if(isLocal){
conf.setMaster("local[*]")
}
//指定以后在哪里读取数据
val sc = new SparkContext(conf)
//当读取数据完后,以后通过参数把他传进来,这样是一行一行的读取
val lines: RDD[String] = sc.textFile(args(1))
//对数据进行整理
val uidAndDate: RDD[(String, String)] = lines.map(line => {
//切割数据
val fields: Array[String] = line.split(",")
//把数据存储到相应的数组里面
val uid: String = fields(0) //存放uid
val date: String = fields(1) //存放日期,注意这些都是string类型
(uid, date)
})
//现在对uid和日期进行处理并存放在数组里面,现在如何对日期进行处理
//先对他按照key进行分组聚合
val grouped: RDD[(String, Iterable[String])] = uidAndDate.groupByKey()
/*val result: mutable.Buffer[(String, Iterable[String])] = grouped.collect().toBuffer
println(result)
//(guid01,CompactBuffer(2018-02-28, 2018-03-01, 2018-03-02, 2018-03-04, 2018-03-05, 2018-03-06, 2018-03-07))*/
val uidAndDateDiff: RDD[(String, (String, String))] = grouped.flatMapValues(t => { //让每一个value值与key合在一起
//先对value里面的元素进行操作
val sorted: List[String] = t.toSet.toList.sorted
//定义一个日期工具类,后面可对日期进行操作
val calendar: Calendar = Calendar.getInstance()
//创建一个日期格式,把日期进行格式化
val sdf: SimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd")
var index = 0
sorted.map(dateStr => {
//把string类型格式的日期转成格式化类型
val date = sdf.parse(dateStr)
//把设置好的日期放到Calendar里面
calendar.setTime(date)
calendar.add(Calendar.DATE, -index)
index += 1
(dateStr, sdf.format(calendar.getTime)) //获取当前时间
})
})
//在完成分组聚合之后再对value map一下 (guid01,2018-02-28), (guid01,2018-03-01),
// val result1: Array[(String, (String, String))] = uidAndDateDiff.collect()
// println(result1.toBuffer)
//guid01,(2018-02-28,2018-02-28))
val result1: RDD[((String, String), String)] = uidAndDateDiff.map(t => {
((t._1, t._2._2), t._2._1) //显示uid,被减去之后的日期,和初始登录日期
})
val res: RDD[((String, String), Iterable[String])] = result1.groupByKey()
//val tuples: Array[((String, String), Iterable[String])] = res.collect()
// println(tuples.toBuffer)
//((guid02,2018-03-01),CompactBuffer(2018-03-01, 2018-03-02, 2018-03-03))
//继续操作
val res2: RDD[((String, String), (Int, String, String))] = res.mapValues(t => { //注意着仅仅只是对value进行处理
//先把整个元组转成列表的形式
val list: List[String] = t.toList
val times: Int = list.size
val beginTime: String = list.head
val lastTime: String = list.last
(times, beginTime, lastTime)
})
val res3: RDD[(String, Int, String, String)] = res2.map(t => {
(t._1._1, t._2._1, t._2._2, t._2._3)
})
println(res3.collect().toBuffer)
sc.stop()
//(guid02,3,2018-03-01,2018-03-03)