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封装关键字,并在非代码环境下使用关键字构建可被执行的测试用例 ...
随机推荐
- P4433 [COCI2009-2010#1] ALADIN
题目描述 给你 n 个盒子,有 q 个操作,操作有两种: 第一种操作输入格式为"1 L R A B",表示将编号为L到R的盒子里的石头数量变为(X−L+1)×A mod B,其中 ...
- [洛谷P5216]DLS 采花
题目大意:有$n$个数,任意排列,排列后第$i$个数会产生贡献当且仅当$1\sim i-1$中的数不是它的因子,问所有排列的贡献和 题解:发现一个数要产生贡献要求所有它的因子在它的右边,设有$cnt_ ...
- 【agc006f】Blackout(神仙题)
[agc006f]Blackout(神仙题) 翻译 给定一个\(n*n\)的网格图,有些格子是黑色的.如果\((x,y),(y,z)\)都是黑色的,那么\((y,x)\)也会被染黑,求最终黑格子数量. ...
- 九省LNOI2018退役记
立个flag不会退役. Day 0: 水一发. 大连大学的键盘敲起来就跟敲纸似的. 膜拜要进队的gqh,yxd,sjq. (都进啦2333) (高斯消元,高原反应,分麾下治……) 给我这只弱鸡烧根香. ...
- 洛谷 P1685 游览 解题报告
P1685 游览 题目描述 顺利通过了黄药师的考验,下面就可以尽情游览桃花岛了! 你要从桃花岛的西头开始一直玩到东头,然后在东头的码头离开.可是当你游玩了一次后,发现桃花岛的景色实在是非常的美丽!!! ...
- 使用rundll32.exe绕过应用程序白名单(多种方法)
0x00 前言 本文演示了白名单AppLocker bypass的最常见和最熟悉的技术.我们知道,出于安全原因,系统管理员添加组策略来限制本地用户的应用程序执行.在上一篇文章中,我们讨论了“ Wind ...
- 《Linux内核设计与实现》学习总结 Chap18
一.准备开始 1.一个确定的bug,但大部分bug通常都不是行为可靠且定义明确的. 2.一个藏匿bug的内核版本. 3.相关内核代码的知识和运气. 二.内核中的bug 1.bug的表象: 明白无误的错 ...
- Qt error ------ incomplete type 'QApplication' used in nested name specifier
没有包含 ‘QApplication’ 头文件
- MySQL内存计算器
MySQL如何使用内存? 首先,介绍MySQL使用内存的一些方法: 1. 会话级别的内存消耗(连接私有内存):如sort_buffer_size等,每个会话都会开辟一个sort_buffer_size ...
- P1792 [国家集训队]种树
P1792 [国家集训队]种树 题目描述 A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树. 园林部门得到指令后,初步规划出n个种树的位置,顺时针编号1到n.并且每 ...