如果有一个实时数据需求:一个用户在指定时间内依次完成了事件A,B,C,D,那就给该用户推送消息。在不使用Flink Cep的情况下,有什么办法呢?
一个用户的行为数据流:"A","B","A","C","B","D","C","A","B","B","C","D",从这段事件流中,用户一共完成两次:ABCD。直接说下实现思路,为了演示方便,这是用系统时间代替事件时间,用户的历史状态保存在内存里,状态的保存方式"0_0_0_0"(ABCD四个事件,初始状态用0表示,后续逐渐替换成时间戳,具体细节看下图)
具体代码如下
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class Test {
public static Map eventMap = new HashMap<>();
public static void main(String[] args) throws Exception{
eventMap.put("A",0);
eventMap.put("B",1);
eventMap.put("C",2);
eventMap.put("D",3);
String[] eventArr = new String[]{"A","B","A","C","B","D","C","A","B","B","C","D"};
cl(eventArr);
}
public static String cl(String[] eventArr)throws Exception{
String result = "0_0_0_0";//记录事件流(ABC)匹配结果
for (String event : eventArr) {
String[] events = result.split("_");
Integer eventIndex = eventMap.get(event);
String lastEventTime = "";
if(eventIndex==0){
//使用系统当前时间当作时间流开始的时间
events[eventIndex] = System.currentTimeMillis()+"";
}else{
lastEventTime = events[eventIndex - 1];
}
result = String.join("_",events);
//如果是最后一个事件C,判断是否有前置事件B,如果有的话说明事件流匹配成功
if(eventIndex == events.length - 1 ){
if(!"0".equals(lastEventTime)){
long endTime = System.currentTimeMillis();
System.out.println("事件流匹配成功!!,事件流开始时间:"+events[eventIndex - 1]+
",事件流结束时间:"+endTime+",时间流耗时:"+(endTime-Long.parseLong(events[eventIndex - 1]))+"ms");
events[eventIndex - 1] = "0";
result = String.join("_",events);
}
}
if(!"0".equals(lastEventTime)){
if(eventIndex>0){
events[eventIndex] = events[eventIndex-1];
events[eventIndex - 1] = "0";
result = String.join("_",events);
}
}
Thread.sleep(new Random().nextInt(300));
}
return result;
}
}
输出
事件流匹配成功!!,事件流开始时间:1660043229079,事件流结束时间:1660043229885,
时间流耗时:806ms
事件流匹配成功!!,事件流开始时间:1660043230402,事件流结束时间:1660043231100,
时间流耗时:698ms