本文用到的数据请自取:
链接:https://pan.baidu.com/s/1CMnDAj4ga4wsvVw-y83BwQ?pwd=op0g
提取码:op0g
案例1:如果用户在2s内连续2次登录失败,我们就判定为恶意登录,发出警告
步骤:
1、读文件、取字段、封装样例类 =》
2、分组(user),KeyedProcessFunction =》
3、继承,状态变量1个:存上次失败的数据
4、先判断是不是登录失败了,如果是就再判断状态变量是不是为空,不为空时判断两次失败是不是在2s内。
代码逻辑:

object LoginWarn {
def main(args: Array[String]): Unit = {
val env = StreamExecutionEnvironment.getExecutionEnvironment
env.setParallelism(1)
//读文件
val value = env.readTextFile("data/LoginLog.csv")
//取字段
value.map(x=>{
val strings: Array[String] = x.split(",")
//封装样例类
Login(strings(0),strings(1),strings(2),strings(3).toLong)
})
//分组
.keyBy(_.userId)
.process(new login_Warn)
.print()
env.execute()
}
}
class login_Warn extends KeyedProcessFunction [String,Login,String]{
//定义一个状态变量,存上一次失败的数据
lazy val last_fail: ValueState[Login] = getRuntimeContext
.getState(new ValueStateDescriptor[Login]("last_fail", classOf[Login]))
override def processElement(i: Login,
context: KeyedProcessFunction[String, Login, String]#Context,
collector: Collector[String]): Unit = {
//判断进来的数据是fail还是success
if(i.state == "fail"){
//先判断状态变量里面有没有值,没值,是第一条fail数据
if(last_fail.value() == null){
//为空,先存为状态变量
last_fail.update(i)
}else{
//不为空,是连续的fail数据,就判断两次失败是不是在 2s 内
if(i.time - last_fail.value().time<2){
//输出预警信息
collector.collect(s"${i.userId}用户在" +
s"${new Timestamp(last_fail.value().time*1000)}和" +
s"${new Timestamp(i.time*1000)}之间连续2次登陆失败,锁定账号")
//输出之后清空状态变量,开始下一轮判断
last_fail.update(i)
}else{
//更新状态变量
last_fail.update(i)
}
}
//数据是success,不满足连续两次是fail,清空状态变量
}else{
last_fail.clear()
}
}
}
***样例类***
//网页登陆样例类
case class Login(userId:String,ip:String,state:String,time:Long)
案例2:如果船在20s以上,2分钟以内连续两次速度超过20,判定故意超速,输出报警信息
步骤:
1、读文件、过滤首行 =》
2、将时间格式转换为时间戳(new SimpleDateFormat()里的parse方法 =》
3、封装样例类 =》
4、分组
5、定义一个状态变量,存上一超速数据 =》
6、判断进来的数据是否超速,如果是就再判断状态变量是不是为空,不为空时判断两次超速是不是在20s以上,2分钟以内。
object AIS_Speed {
def main(args: Array[String]): Unit = {
val env = StreamExecutionEnvironment.getExecutionEnvironment
env.setParallelism(1)
//读文件
val value = env.readTextFile("data/ship_trajectory.csv")
value
.filter(!_.contains("mmsi"))
.map(x => {
val strings: Array[String] = x.split(",")
val format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
val date: Date = format.parse(strings(1))
//getTime得到的时间戳是以毫秒为单位,所以要除以1000,变成秒。这里不用除是因为时间间隔太小要精确到毫秒计算。
val time: Long = date.getTime
aisCase(strings(0), time, strings(2), strings(3),
strings(4).toDouble, strings(5), strings(6))
})
.keyBy(_.mmsi)
.process(new aisSpeed_Warn(20))
.print()
env.execute()
}
}
class aisSpeed_Warn(x:Double) extends KeyedProcessFunction [String,aisCase,String]{
//定义一个状态变量,存上一次超速的数据
lazy val last_ais: ValueState[aisCase] = getRuntimeContext
.getState(new ValueStateDescriptor[aisCase]("last_ais", classOf[aisCase]))
override def processElement(i: aisCase,
context: KeyedProcessFunction[String, aisCase, String]#Context,
collector: Collector[String]): Unit = {
//判断进来的数据是否超速
if(i.speed > x){
//先判断状态变量里面有没有值,即判断之前有没有速度大于10的记录
if(last_ais.value() == null){
//为空,更新状态变量
last_ais.update(i)
}else{
//不为空,即已经有超速记录,就判断两次超速是不是在 10s 内
if((i.time - last_ais.value().time > 20000) & (i.time-last_ais.value().time)< 120000){
//输出预警信息
collector.collect(s"${i.mmsi}船" +
s"在${last_ais.value().time}速度为${last_ais.value().speed}," +
s"在${i.time}速度为${i.speed},判断故意超速,发出警报")
//输出之后清空状态变量,开始下一轮判断
last_ais.update(i)
}else{
//更新状态变量为最新的数据
last_ais.update(i)
}
}
//不满足连续两次超速,清空状态变量
}else{
last_ais.clear()
}
}
}
***样例类***
case class aisCase(mmsi:String,time:Long,lng:String,lat:String,speed:Double,course:String,id1:String)
案例3:如果用户的行为由pv变成buy就代表他购买了商品,则输出信息
步骤:
1、读数据,封装样例类 =》
2、根据(用户id,商品id)分组 =》3、定义一个状态变量,存上一条用户行为 =》
4、进行行为的判断是否由pv行为变成buy行为:状态变量为空时更新状态变量,当新的数据是buy,前一条状态是pv时,输出提示信息,否则只更新状态变量
object BuyWarn {
def main(args: Array[String]): Unit = {
val env = StreamExecutionEnvironment.getExecutionEnvironment
env.setParallelism(1)
//读文件
val value = env.readTextFile("data/UserBehavior.csv")
//取字段
value.map(x=>{
val strings: Array[String] = x.split(",")
//封装样例类
Goods(strings(0),strings(1),strings(2),strings(3),strings(4).toLong)
})
.keyBy(x=>(x.userId,x.comId))
.process(new userShop)
.print()
env.execute()
}
}
class userShop extends KeyedProcessFunction[(String,String),Goods,String]{
//定义一个状态变量,存上一条用户行为
lazy val last_user: ValueState[Goods] = getRuntimeContext
.getState(new ValueStateDescriptor[Goods]("last_user", classOf[Goods]))
override def processElement(i: Goods,
context: KeyedProcessFunction[(String,String), Goods, String]#Context,
collector: Collector[String]): Unit = {
//先判断状态变量中有没有值
if(last_user.value() == null){
//不管来的是什么数据,都更新状态
last_user.update(i)
}
if(i.state == "buy" && last_user.value().state == "pv"){
//新的数据是buy,前一条状态是pv,才输出提示信息
collector.collect(s"${i.userId}用户购买了${i.comId}商品,交易成功,具体信息为${last_user.value()},${i}")
}else{
last_user.update(i)
}
}
}
***样例类***
//用户的行为样例类
case class Goods(userId:String,comId:String,cat:String,state:String,time:Long)
文章介绍了使用ApacheFlink流处理框架实现的三个示例,包括检测恶意登录、AIS船速超速报警以及用户行为转变的购买行为识别。通过KeyedProcessFunction和状态变量,实现实时监控并触发相应警告。

被折叠的 条评论
为什么被折叠?



