Esper复杂事务处理一小时入门
来自小韩
什么是Esper
想要认识Esper,先要了解CEP(Complex Event Processing),到处都有,并且各方理解也有偏差,我就不赘述了。
Esper就是CEP的一个java的开源实现。
Esper官方网址:http://www.espertech.com/
Esper的特性
在探究Esper特性之前,我们先总结一下复杂事件的特性:
- 类型多样,不易建模
- 场景不可控,随时可能新增场景
- 逻辑复杂,难于描述
- 既需要汇总规律,又不准数据落地。
场景举例:
股市实时K线图、网站恶意操作监测、用户登入控制、实时数据统计等
针对复杂事件的这些特性,Esper具有相应的性质:
- 实时响应
- 极速扩展新事件
- 语法描述能力强大、类sql
事件和处理流程
一个基本的例子
引用Esper就不说了,直接搜maven esper,添加以来就好。
/*定义事件模型*/
public class Coder {
private String Name;
private int age;
private double Salary;
//省略getter/setter
}
//
public class HelloEsperApp {
public static void main(String[] args) throws InterruptedException {
EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider();
EPAdministrator admin = epService.getEPAdministrator();
//指定事件模型
String coderModel = Coder.class.getName();
//描述复杂事件
String epl = "select name,salary,age from " + coderModel;
EPStatement state = admin.createEPL(epl);
//添加事后处理
state.addListener(new HelloEsperListener());
EPRuntime runtime = epService.getEPRuntime();
//模拟事件发生
for (int i = 0; i < 10; i++) {
Coder coder = new Coder();
coder.setName("coder"+i);
coder.setAge(20+i);
runtime.sendEvent(coder);
}
}
}
import com.espertech.esper.client.UpdateListener;
/** 实现UpdateListener接口,来定义事件的后置处理过程 **/
public class HelloEsperListener implements UpdateListener {
public void update(EventBean[] arg0, EventBean[] arg1) {
try {
System.out.println("coder: name-"+arg0[0].get("name") + " age-"+arg0[0].get("age"));
}catch(Exception e) {
e.printStackTrace();
}
}
小心的分享:笔者认为任何一个项目的学习都可以分为两步,1.看他暴露了多少给你(用起来是否清晰);2.看他隐藏了多少细节(实现得是否精致)
一张图简单描述一下Esper给我们暴露了什么:
其中,后置处理方式的subscribe本文暂不提及。
Esper支持的模型类型
前面的例子中,我们使用一个bean作为事件模型。这样做很多时候都存在局限性,当有新的事件模型需要被加入时,我们必须要定义新的类,实际上,在实际应用中,bean很少被使用。
Esper支持丰富的事件模型定义方式,包括java类、Map、List、XML。
例如使用Map来定义事件模型:
Map<String, Object> blog = new HashMap<String, Object>();
blog.put("url", String.class);
blog.put("title", String.class);
Map<String, Object> coder = new HashMap<String, Object>();
coder.put("name", String.class);
coder.put("salary", int.class);
coder.put("friends", List.class);
coder.put("blogKey", "Blog");
// 注册blog模型到esper
admin.getConfiguration().addEventType("Blog", blog);
// 注册coder到Esper
admin.getConfiguration().addEventType("Coder", coder);
这之后,我们就可以对Coder事件模型进行EPL事件描述了。
EPL语法
关于语法,我们大致讲一下,到能帮助大家整体理解Esper的程度,之后会单独写文章来分享语法技巧。
基本语法
以上面的Coder模型为例,类SQL部分,我们快速带过:
#实时计算出当前进入引擎的所有程序员的平均工资、最高工资。
select name,Blog.title,salary,avg(salary) as avgSalary,max(salary) as maxSalary from Coder where salary>1000;
#其他的例如 and、or、not、in、order by、group by、having、join等基本都与SQL标准一致
与SQL不同的地方,主要体现了实时性,与sql的持久数据形成对比我们列四点最重要的学习一下:insert、窗格、context、pattern。
insert
首先用SQL的视角去想象,好像把数据保存起来这样的动作在Esper这样实时处理的工具中好像确实没有场景。
实际上insert在Esper中做的是转发的角色。即把某事件模型类的事件经过EPL运算后,insert成另外一种事件,去触发另外事件的处理流程。看例子:
//在前文Coder的基础上,给Coder加上团队标志,再定义一个Team事件模型
Map<String, Object> coder = new HashMap<String, Object>();
coder.put("name", String.class);
coder.put("salary", int.class);
coder.put("teamName", String.class);
Map<String, Object> team = new HashMap<String, Object>();
team.put("teamName", String.class);
team.put("totalSalary", int.class);
admin.getConfiguration().addEventType("Coder", coder);
admin.getConfiguration().addEventType("Team", team);
String epl4CoderIn = "insert Team(teamName, totalSalary) select teanName,sum(salary) as totalSalary from Coder groupby teamName";
String epl4TeamIn = "select teamName, totalSalary from Team";
EPStatement state = admin.createEPL(epl4CoderIn);
EPStatement state = admin.createEPL(epl4TeamIn);
state.addListener(new TeamEventListener());
这时,每当有Coder类型的事件流入,就转化为新的Team事件去触发Team的流程。Esper可以基于此实现事件流。
窗格
窗格应该是最有别于SQL的特性了,Esper的事件收集器支持事件积攒,分为两种积攒方式,时间和数量。
时间窗格
select name, avg(salary) from Coder.win:time(5 sec);
计算5秒内进入引擎的Coder的平均工资,看图理解:
每有新的事件进入,就会触发事件收集器回溯5秒,找到这五秒内收到的所有事件,并一同发给后置处理器。时间批量窗格
select name, avg(salary) from Coder.win:time_batch(5 sec);
看图理解:
在事件批量窗格中,事件的进入不触发后置处理,只有满了一个批量单位才会进行提交。例如在股市K线图的实时绘制中就采用这种机制。
事件窗格支持的时间定义,小到毫秒大到年,包括msec、sec、min、hour、day、week、month、year。例如我们要定义一个周期为一天5小时20分的窗格,可以写作:
1 day 5 hour 20 min数量窗格
数量窗格跟事件窗格一样也分普通和批量,我们先来看一下语法例子:
select name, avg(salary) from Coder.win:length(5);
select name, avg(salary) from Coder.win:length_batch(5);
非批量情况下,事件进入就会触发收集引擎回溯最近的五个事件,批量提交给后置处理器;批量情况下则是,每满5个事件才提交一次,不满则等待。
context
即使是同样的事件,也有很多情况下需要分组处理,context为Esper提供一种组别定义的能力,从而让事件流入不同的处理组中我们结合前面的窗格举一个实际的例子。
场景:游戏对局匹配
规则:十个人一组,进行5V5游戏,玩家按等级分为青铜、白银、黄金、白金、钻石、王者六种,为了保证游戏竞技性,只有级别相同的玩家才能共同进行一局游戏。
如果只是十个人对战,那个很简单,我们只需要按照前文介绍的,数量批量提交窗口,定义一个容量为10的窗格,每满十个,就交给后置处理器去创建对局。但是现在的场景又加入了玩家水平等级制,这时,就需要Context帮忙了。
// 省略Player模型的创建过程
// 创建context以Player的level属性作为组分割条件
String createContext = "create context forLevel partition by level from Player";
// 带上context前缀
String match = "context forLevel select * from Player.win:length_batch(10)";
admin.createEPL(createContext);
EPStatement state = admin.createEPL(match);
state.addListener(new StartGameListener());
pattern
pattern具有极强大的逻辑描述能力,本文暂不介绍,后续独立发文。
进程模型分析
其实看过了前面的内容这一部分,我们先搬官网的图出来看看:
不知道大家什么感觉,总之我是不愿意看的...我们来翻译一下第一张图:
官网给出的第二张事件流收集原理实际上可以看做是引擎入口处的EPL语句的解析过程。引擎中将事件分了三级缓存:
入门先到这里!
Esper复杂事务处理一小时入门的更多相关文章
- 《Qt Quick 4小时入门》学习笔记4
http://edu.csdn.net/course/detail/1042/14806?auto_start=1 Qt Quick 4小时入门 第七章:处理鼠标与键盘事件 1.处理鼠标事件 鼠标信号 ...
- 《Qt Quick 4小时入门》学习笔记3
http://edu.csdn.net/course/detail/1042/14807?auto_start=1 Qt Quick 4小时入门 第八章:Qt Quick中的锚(anchors)布局 ...
- 《Qt Quick 4小时入门》学习笔记2
http://edu.csdn.net/course/detail/1042/14805?auto_start=1 Qt Quick 4小时入门 第五章:Qt Quick基本界面元素介绍 1. ...
- 《Qt Quick 4小时入门》学习笔记
http://edu.csdn.net/course/detail/1042/14804?auto_start=1 Qt Quick 4小时入门 第五章:Qt Quick里的信号与槽 QML中 ...
- 一小时入门PHP
[版权申明:本文系作者原创,转载请注明出处] 文章出处:[http://blog.csdn.net/sdksdk0/article/details/52332296](http://blog.csdn ...
- 一小时入门 Python
因为需求, 需要用到py, 所以来学学py, 因为有java基础 一小时入门py语法是不成问题的, 但是仅仅入门基础语法而已, 不涉及算法,不涉及大数据,机器学习,人工智能, 但是py这么火爆,就在于 ...
- iOS 开发-- Runtime 1小时入门教程
1小时让你知道什么是Objective-C Runtime,并对它有一定的基本了解,可以在开发过程中运用自如. 三.Objective-C Runtime到底是什么东西? 简而言之,Objective ...
- mongodb 两小时入门
传统的计算机应用大多使用关系型数据库来存储数据,比如大家可能熟悉的MySql, Sqlite等等,它的特点是数据以表格(table)的形式储存起来的.数据库由一张张排列整齐的表格构成,就好像一个Exc ...
- 2小时入门Robot Framework
1.介绍 1.1.介绍Robot Robot Framework是一个基于关键字驱动的自动化测试框架.通过该框架,测试人员可使用python封装关键字,并在非代码环境下使用关键字构建可被执行的测试用例 ...
随机推荐
- Cure HDU - 5879(预处理+技巧)
Cure Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- BZOJ 3339: Rmq Problem
3339: Rmq Problem Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 1075 Solved: 549[Submit][Status][ ...
- Linux系统启动详解(三)
上节已系统initramfs已启动完成,将系统控制权交给了真正的rootfs的/sbin/init,下面就是/sbin/init干活的时间了. 4 /sbin/init initramfs ...
- Android资源混淆 + 混淆忽略 .so库
安装包立减1M--微信Android资源混淆打包工具http://mp.weixin.qq.com/s?__biz=MzAwNDY1ODY2OQ==&mid=208135658&idx ...
- 解题:BJOI 2006 狼抓兔子
题面 可以看出来是最小割,然后你就去求最大流了 这么大的范围就是让你用网络流卡的?咋想的啊=.=??? 建议还是老老实实用 平面图最小割等于其对偶图最短路 这个东西来做吧,虽然这个东西跑的也挺慢的,最 ...
- 流媒体协议之RTSP服务端的实现20180629
RtspServer是参考了live555和jrtplib实现的,但代码全部是重新书写的,所以不依赖于任何第三方库即可编译和运行, 目前仅支持h264和G711格式,这是rtp打包时决定的,后续将不断 ...
- ASP.NET MVC 3 常用
http://blog.csdn.net/churujianghu/article/details/7297358 1.ASP.NET MVC 3 如何去除默认验证 这个默认验证是在web.confi ...
- 线程属性API
数据类型:pthread_attr_t 操作API: // 初始化线程属性 int pthread_attr_init(pthread_attr_t *attr);// 初始化为系统支持的所有属性的默 ...
- django中模板变量与内置标签以及过滤器
本文参考 官方文档 . 一 模板变量 格式: {{ variable_name }} variable_name 命名规则与变量命名规则类似,允许字符数字下划线,不允许标点. variable_ ...
- jenkins集成sonarqube代码审核
目前在持续集成领域,除了后起之秀travis ci,在老牌工具中,最著名的还是非jenkins莫属.本篇文章简单的说一声jenkins与sonarqube的集成来实现代码的静态审核. 在这里不详细罗列 ...