进程模型
主要解释一下 Esper 是怎么处理事件的,即Esper的进程模型。
1、UpdateListener
UpdaterListener
是 Esper 提供的一个接口,用于监听某个 EPL 在引擎中的运行情况,即事件进入并产生结果后会通知 UpdateListener
。接口如下
import com.espertech.esper.client.EventBean; public interface UpdateListener { public void update(EventBean[] newEvents, EventBean[] oldEvents); }
接口很简单,就一个 update
方法,其中包括两个 EventBean
数组。EventBean
中有一个最常用的 get
方法,是用来得到 EPL 中某个字段的值。
如下代码:假设 newEvents 长度为1
// 能得到进入的User事件的name属性值 EPL:select name from User newEvents[0].get("name") // 能得到5秒内进入引擎的User事件数量有多少 EPL:select count(*) from User.win:time(5 sec) newEvents[0].get("count(*)");
get
方法最常用,此外还有 getUnderlying
等方法,
2、Insert 和 Remove Stream
Insert
表示进入引擎,Remove
表示移出引擎,事件在 Esper 中会因为某类EPL才会经历这两种状态。对应于 UpdateListener
接口就是 newEvents
和 oldEvents
,因为处于这两种状态的事件不一定只有一个,所以 newEvents
和 oldEvents
就是数组形式。
举例如下
EPL:select * from User
从此图可以看出,随着时间推移,每个进入到引擎的 W
事件都是 newEvents
,即 Insert Stream
。W
后括号里的值为属性值(500、100、...),可忽略。
有人可能要问了,为什么这里 oldeEvents
什么都没有。那是因为 EPL
的关系。看下面的例子。
EPL:select * from User.win:length(5)
注:win:length(5)
是个 view
(可以把view理解为一个窗口),这里先暂时理解为 Esper 开放一个空间并最多可同时存放 5
个事件(此空间其实就是大小为 5
的数组)
由图可知,length window
可存放 w1
,w2
等事件,在 w6
事件进入之前,每个事件进入都属于 newEvents
。
直到 w6
进入后,length window
不能容纳 w1~w6
的事件,必须把 w1
事件移出,即 w1
为 oldEvents
。
length window
就像一个队列,每当事件进入队列时,就会触发 updateListener
并告知有新事件进入。当队列满了,再进入一个新事件时,Esper 会触发 UpdateListener
告知有新事件进入并且有旧事件移出,正如上图所示的 w6
和 w1
。
实际上这个EPL触发监听器都只能看到 newEvents
,看不到 oldEvents
。如果想看到 oldEvents
,EPL 要改写一下:
EPL:select irstream * from User.win:length(5)
默认情况下,Esper 认为你只想让 newEvents
触发监听器,即 istream(insert stream)
。如果想让 oldEvents
触发监听器,那么为 rstream(remove stream)
。如果两个都想,那么为 irstream
。当然这个默认情况是可以配置的,以后会说到这个问题。
3、Filter 过滤、Where 条件查询
EPL 有两种过滤事件的方式,
一种是过滤事件进入view,即
Filter
。一种是让事件都进入view,但不触发
UpdateListener
,即where
子句。
Filter:过滤器
-- Apple事件进入Esper,只有 amount 大于 200 才能进入 win:length,并且 length 长度为5 EPL:select * from Apple(amount>200).win:length(5)
从图上可以看出,只有amount
大于200
,Esper才允许Apple事件进入view,并且作为一个 newEvent
触发 UpdateListener
。
Where:条件查询
-- Apple事件进入Esper 并进入win:length(5),但是只有 amount 大于 200 的才能触发 UpdateListener EPL:select * from Apple.win:length(5) where amount>200
由图上可以看出,Apple事件先进入view,然后才被 where
子句过滤,以至于被过滤掉的事件不会作为 newEvent
触发 UpdateListener
4、Aggregation 聚合、 Grouping 分组
之前说过 EPL
是类 SQL
语法,所以也会有聚合和分组的功能。语法和SQL基本一样,如下代码:
-- 统计进入的5个Apple事件,amount的总数是多少 select sum(amount) from Apple.win:length_batch(5) -- 统计进入的5个Apple事件,amount的总数是多少,并按照price分组 select price, sum(amount) from Apple.win:length_batch(5) group by price -- 统计进入的5个Apple事件,amount的总数和name,并按照price分组 select price, name, sum(amount) from Apple.win:length_batch(5) group by price
最后一个和前一个的区别在于 name
也在统计的范围内,所以当 name
和 price
都一样的两个事件进入Esper,会有两个一模一样的事件作为 newEvent
触发 UpdaterListener
,即 price,name,sum(amount)
都一样。当然要是 group by name, price
的话,就只会有一个事件触发监听器了。
未经允许请勿转载:程序喵 » Esper教程 —— Esper 进程模型是什么(3)