1 数据
0 管理员登录
1 首次登录
2 上线
3 下线
1|2016年2月1日,星期一,10:01:08|10.51.4.168|李明克星|法师|男|1|0|0/800000000
1|2016年2月1日,星期一,10:01:12|10.117.45.20|风道|道士|男|1|0|0/800000000
4|2016年2月1日,星期一,10:01:27|10.51.4.168|李明克星|法师|男|2|0|0/800000000
4|2016年2月1日,星期一,10:01:30|10.117.45.20|风道|道士|男|2|0|0/800000000
4|2016年2月1日,星期一,10:01:35|10.51.4.168|李明克星|法师|男|3|0|273/800000000
1|2016年2月1日,星期一,10:01:37|10.171.198.176|主宰|武士|男|1|0|0/800000000
4|2016年2月1日,星期一,10:01:37|10.117.45.20|风道|道士|男|3|0|0/800000000
4|2016年2月1日,星期一,10:01:42|10.51.4.168|李明克星|法师|男|4|0|538/800000000
4|2016年2月1日,星期一,10:01:45|10.117.45.20|风道|道士|男|4|0|157/800000000
4|2016年2月1日,星期一,10:01:47|10.51.4.168|李明克星|法师|男|5|0|750/800000000
1|2016年2月1日,星期一,10:01:49|10.168.8.103|潮流哥|法师|男|1|0|0/800000000
4|2016年2月1日,星期一,10:01:54|10.51.4.168|李明克星|法师|男|6|0|872/800000000
4|2016年2月1日,星期一,10:01:54|10.117.45.20|风道|道士|男|5|0|340/800000000
4|2016年2月1日,星期一,10:02:00|10.51.4.168|李明克星|法师|男|7|0|987/800000000
4|2016年2月1日,星期一,10:02:01|10.117.45.20|风道|道士|男|6|0|453/800000000
4|2016年2月1日,星期一,10:02:05|10.51.4.168|李明克星|法师|男|8|0|1243/800000000
4|2016年2月1日,星期一,10:02:06|10.117.45.20|风道|道士|男|7|0|684/800000000
4|2016年2月1日,星期一,10:02:14|10.51.4.168|李明克星|法师|男|9|0|1375/800000000
4|2016年2月1日,星期一,10:02:16|10.117.45.20|风道|道士|男|8|0|905/800000000
1|2016年2月1日,星期一,10:02:22|10.168.8.103|潮流锅|武士|男|1|0|0/800000000
4|2016年2月1日,星期一,10:02:23|10.117.45.20|风道|道士|男|9|0|1120/800000000
4|2016年2月1日,星期一,10:02:24|10.51.4.168|李明克星|法师|男|10|0|1500/800000000
........
2 代码
TimeUtils .scala
package gamelog
import java.text.SimpleDateFormat
import java.util.Calendar
object TimeUtils {
val simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
val calendar = Calendar.getInstance()
def apply(time: String) = {
calendar.setTime(simpleDateFormat.parse(time))
calendar.getTimeInMillis
}
def getCertainDayTime(amount: Int): Long ={
calendar.add(Calendar.DATE, amount)
val time = calendar.getTimeInMillis
calendar.add(Calendar.DATE, -amount)
time
}
}
package gamelog
/**
* 事件类型枚举
* 0 管理员登陆
* 1 首次登陆
* 2 上线
* 3 下线
* 4 升级
*/
object EventType {
val REGISTER = "1"
val LOGIN = "2"
val LOGOUT = "3"
val UPGRADE = "4"
}
FilterUtils.scala
package gamelog
import org.apache.commons.lang3.time.FastDateFormat
object FilterUtils {
val dateFormat = FastDateFormat.getInstance("yyyy年MM月dd日,E,HH:mm:ss")
def filterByTime(fields: Array[String], startTime: Long, endTime: Long): Boolean = {
val time = fields(1)
val logTime = dateFormat.parse(time).getTime
logTime >= startTime && logTime < endTime
}
def filterByType(fields: Array[String], evenType: String): Boolean = {
val _type = fields(0)
evenType == _type
}
def filterByTypes(fields: Array[String], eventTypes: String*): Boolean = {
val _type = fields(0)
for(et <- eventTypes){
if(_type==et)
return true
}
false
}
def filterByTypeAndTime(fields: Array[String], eventType: String, beginTime: Long, endTime: Long): Boolean = {
val _type = fields(0)
val _time = fields(1)
val logTime = dateFormat.parse(_time).getTime
eventType == _type && logTime >= beginTime && logTime < endTime
}
}
2.1 新增用户
package gamelog
import org.apache.spark.{SparkConf, SparkContext}
object GameKPI {
def main(args: Array[String]): Unit = {
val queryTime = "2016-02-01 00:00:00"
val beginTime = TimeUtils(queryTime)
val endTime = TimeUtils.getCertainDayTime(+1)
val conf = new SparkConf().setAppName("GameKPI").setMaster("local[*]")
val sc = new SparkContext(conf)
//切分后的数据
val splitedLogs = sc.textFile("d://Gamelog.txt").map(_.split("\\|"))
//过滤后并缓存
val filteredLogs = splitedLogs.filter(fields => FilterUtils.filterByTime(fields,beginTime,endTime))
.cache()
//日新增用户
val dnu = filteredLogs.filter(fields => FilterUtils.filterByType(fields,EventType.REGISTER))
.count()
println(dnu)
//
sc.stop()
}
}
2.2 活跃用户
//Daily Active Users
val dau = filteredLogs.filter(fields => FilterUtils.filterByTypes(fields,EventType.REGISTER,EventType.LOGIN))
.map(_(3))
.distinct()
.count()
println(dau)
sc.stop()
2.3 留存率
// 留存率:某段时间的新增用户数记为A,经过一段时间后,仍然使用的用户占新增用户A的比例即为留存率
// 次日留存率(Day 1 Retention Ratio) Retention Ratio
// 日新增用户在+1日登陆的用户占新增用户的比例
val t1 = TimeUtils.getCertainDayTime(-1)
val lastDayRegUser = splitedLogs.filter(fields => FilterUtils.filterByTypeAndTime(fields, EventType.REGISTER, t1, beginTime))
.map(x => (x(3), 1))
val todayLoginUser = filteredLogs.filter(fields => FilterUtils.filterByType(fields, EventType.LOGIN))
.map(x => (x(3), 1))
.distinct()
val d1r: Double = lastDayRegUser.join(todayLoginUser).count()
println(d1r)
val d1rr = d1r / lastDayRegUser.count()
println(d1rr)