Esper是一个Java开发并且开源的轻量级和可扩展的事件流处理和复合事件处理引擎,并提供了定制的事件处理语言(EPL)。
应用场景
某个用户在请求登录服务时,n秒内连续m次未登录成功,可视为该ip在暴力破解密码。又或者:用户在页面上的操作间隔超过n秒即认为该用户已关闭该网页。也许上面的几个例子不够好或者已经有别的方式实现,但是Esper确实能够将其抽象成多个关联的事件进行处理。
源码地址: http://www.espertech.com/esper/distributions/
事件的分类
简单事件处理(SEP):基于单个事件,即:触发并响应,通常采用点对点(Queue)和发布和订阅(Topic)[类似观察者模式];
事件流处理(ESP):事件的出发需要分析事件流,分析采用基于事件窗口和事件数量窗口的方式;
复合事件处理(CEP):先捕获各种细微基础事件,然后分析整体找出的更有意义的事件。
EPL与SQL的区别
SQL:每执行一次SQL语句就会执行一次查询,存储的是具体的数据。
EPL:当满足到设定的执行条件后才触发执行,存储的是具体的功能性操作(如:查询、删除、插入等)而非操作所需的数据。
Esper的适配器
输入输出适配器,API提供对实时数据流输入到Esper容器,或事件输出的各种途径或方式,该过程需将实时数据流转成实时事件流,并以Object、Map、Node形式的事件发送的引擎;
输入适配种类:
CVS,Spring JMS,HTTP,Socket、关系型数据库
输出适配种类:
Spring JMS,HTTP,XML,JSON
事件类型
POJO、Map、Object Array,XML
示例程序:
orderBean.java
// 引用数据类型类定义
public class orderBean {
private String key;
private String value;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
orderEvent.java
// 事件流单元实现类
public class orderEvent {
//基本数据类型
private String name;
private int salary;
// 集合数据类型,数据项成员为引用数据类型
private List<orderBean> orderBeans;
// 集合数据类型,KEY为基本数据类型,VALUE为引用数据类型
private Map<Integer, orderBean> orderMap;
// 引用数据类型
private orderBean bean;
// 对应事件流中orderBeans属性获取
public String getOrderBeans(int index) {
return orderBeans.get(index).getValue();
}
// 对应事件流中orderBeans属性设置
public void setOrderBeans(List<orderBean> orderBeans) {
this.orderBeans = orderBeans;
}
// 测试使用
public String getOrderBeanListString(int index){
orderBean bean = orderBeans.get(index);
return bean.getKey()+":"+bean.getValue();
}
// 对应事件流中orderMap属性获取
public String getOrderMap(int id) {
return orderMap.get(id).getValue();
}
// 对应事件流中orderMap属性设置
public void setOrderMap(Map<Integer, orderBean> orderMap) {
this.orderMap = orderMap;
}
public orderBean getBean() {
return bean;
}
public void setBean(orderBean bean) {
this.bean = bean;
}
public orderEvent() {
}
public orderEvent(String name, int salary) {
this.name = name;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
}
orderListener.java
/**
* 用于监听某个EPL在引擎中的运行情况,事件进入并产生结果后会回调UpdateListener
* 必须实现 UpdateListener 接口
*/
public class orderListener implements UpdateListener {
/**
* arg0对应newEvent,arg1对应oldEvent
*/
@Override
public void update(EventBean[] arg0, EventBean[] arg1) {
if (null != arg0) {
System.out.println("orderEvent Count is "+arg0[0].get("result"));
} else {
System.out.println("EventBean is Null ");
}
}
}
orderMainTest.java
public class orderMainTest {
public static void main(String[] args){
// 添加配置(包所在路劲),方面后面的引用自动添加包名前缀
Configuration config = new Configuration();
config.addEventTypeAutoName("cn.chenx.esper");
//
EPServiceProvider epServiceProvider = EPServiceProviderManager.getDefaultProvider(config);
EPAdministrator epAdmin = epServiceProvider.getEPAdministrator();
// 计算平均数值
String epsql = "select avg(salary) as result from orderEvent.win:length_batch(3)";
epAdmin.createEPL(ctsql);
EPStatement epstate = epAdmin.createEPL(epsql);
epstate.addListener(new orderListener());
EPRuntime epRuntime = epServiceProvider.getEPRuntime();
//
for (int i=0;i<3;i++){
int seed = (int)(Math.random()*100);
orderEvent event = new orderEvent("张"+seed, 100+seed);
System.out.println("seed name:"+event.getName()+",salary:"+event.getSalary());
orderBean bean = new orderBean();
bean.setKey("BeanKey:"+i);
bean.setValue("BeanValue:"+i);
event.setBean(bean);
List<orderBean> list = new ArrayList<orderBean>();
for (int j=0;j<10;j++){
bean = new orderBean();
bean.setKey("ListKey:"+j);
bean.setValue("ListValue:"+j);
list.add(bean);
}
event.setOrderBeans(list);
Map<Integer, orderBean> map = new HashMap<Integer, orderBean>();
for (int k=0; k<10;k++){
bean = new orderBean();
bean.setKey("MapKey"+k);
bean.setValue("MapValue"+k);
map.put(k, bean);
}
event.setOrderMap(map);
epRuntime.sendEvent(event);
}
}
}
输出结果:
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
className is orderEvent
epsql:select avg(salary) as result from orderEvent.win:length_batch(3)
seed name:张50,salary:150
seed name:张59,salary:159
seed name:张86,salary:186
orderEvent Count is 165.0