Esper学习之十二:EPL语法(八)
今天的内容十分重要,在Esper的应用中是十分常用的功能之一。它是一种事件集合,我们可以对这个集合进行增删查改,所以在复杂的业务场景中我们肯定不会缺少它。它就是Named Window。
由于本篇篇幅较长,希望各位童鞋慢慢阅读,并仔细研究文档中或者我给出的例子。
1.Create Named Window
本篇的开头有说过named window是一种事件集合,它可以存储一种类型或多种类型的事件。如果我们不移除named window中的事件,那么事件应该存在生命周期,否则事件过多会有内存溢出的风险。所以我们在创建named window的时候会附带事件的过期策略,而各种过期策略就是用view来表达。named window的创建方式有三种:a.用已有的事件结构创建;b.自定义named window存放的事件格式;c.将已有的named window中包含的事件写入到新的named window中,即复制named window。
a.Creation by Modelling after an Existing Type
语法如下:
- [context context_name] create window window_name.view_specifications [as] [select list_of_properties from] event
1)context是关键字,后面跟着之前定义的context的名称。关于context的内容,请参看《Esper学习之三:Context》
2)create window后跟着要创建的named window的名字,且具有唯一性。名字后面紧跟着的“.”是用来连接事件过期策略的,即view。常用的view有win:length,win:length_batch,win:time,win:time_batch,std:unique,std:groupwin及自定义view等等,并且特定的view可以连用。PS:view的相关内容我打算在EPL语法讲解完之后就为各位呈上,以免影响其他章节的学习。
3)select子句表示将某个事件定义中的全部或者某些属性作为named window所维护的事件属性。如果将某个事件的所有属性都加入到named window中,则可以通过select子句前的as连接事件名称,并且省略select子句。这个将在接下来的例子进行说明。
举几个例子说明下:
- // FruitWindow保持最近10分钟的Apple事件
- create window FruitWindow.win:time(10 min) as Apple
- // FruitWindow保持最近5分钟的Apple事件,但只包含size和price属性
- create window FruitWindow.win:time(5 min) as select size, price from Apple
b.Creation By Defining Columns Names and Types
和上一种创建方式不同,Esper允许自己指定named window能维护哪些属性,而不是通过别的事件定义来指定。语法如下:
- [context context_name]
- create window window_name.view_specifications [as] (column_name column_type[,column_name column_type [,...]])
column_name表示属性名称,column_type表示属性类型。属性可以是一个,也可以是多个,多个用逗号分隔。示例如下:
- // 创建包含普通属性的named window
- create window SecurityEvent.win:time(30 sec) (ipAddress string, userId String, numAttempts int, properties String[])
- // 创建包含事件类型属性的named window
- create schema SecurityData (name String, roles String[])
- create window SecurityEvent.win:time(30 sec) (ipAddress string, userId String, secData SecurityData, historySecData SecurityData[])
c.Populating a Named Window from an Existing Named Window
这一节在文档中并没有放到create named window里,不过我认为这也是一种创建方式,所以就放在这里讲解了。这种创建方式很容易懂,就是将已经存在的named window中的event写到新的named window中。语法如下:
- [context context_name] create window window_name.view_specifications as windowname insert [where filter_expression]
windowname后面紧跟insert,表示将该window中的事件插入到新建的named window中。where filter_expression表示过滤插入的事件。实例如下:
- create window ScratchBuyOrders.win:time(10) as OrdersNamedWindow insert where side = 'buy'
以上就是三种创建方式,另外还有一个注解的使用,可以使触发时往Listener中传入的事件是数组或者map形式。这个需要各位自己调试的时候才能看到效果。实例如下:
- // 以数组形式反馈给UpdateListener
- @EventRepresentation(array=true)create window FooWindow.win:time(5 sec) as (string prop1)
- // 以Map形式反馈给UpdateListener
- @EventRepresentation(array=false)create window FooWindow.win:time(5 sec) as (string prop1)
- ... equals ...
- create window FooWindow.win:time(5 sec) as (string prop1)
2.Inserting Into Named Windows
创建好named window以后,我们就可以往里面插入事件了。插入的语法很简单,基本上和insert into语法一样。关于insert into,请参见《Esper学习之八:EPL语法(四)》。下面直接举几个例子:
- 1)
- // create named window with some properties of OrderEvent
- create window OrdersWindow.win:keepall() as select symbol, volume, price from OrderEvent
- // insert into events to named window
- insert into OrdersWindow(symbol, volume, price) select name, count, price from FXOrderEvent
- ... equals ...
- insert into OrdersWindow select name as symbol, vol as volume, price from FXOrderEvent
- 2)
- // create named window with POJO
- create window OrdersWindow.win:time(30) as com.mycompany.OrderEvent
- // insert into events to named window
- insert into OrdersWindow select * from com.mycompany.OrderEvent(symbol='IBM')
- 3)
- // create named window
- create window OrdersWindow.win:time(30) as select *, price as derivedPrice from OrderEvent
- // insert into events to named window with custom function
- insert into OrdersWindow select *, MyFunc.func(price, percent) as derivedPrice from OrderEvent
- 4)
- // create named window
- create window OrdersWindow.win:time(30) as select *, price as priceTotal from OrderEvent
- // insert into events to named window
- insert into OrdersWindow select *, price * unit as priceTotal from ServiceOrderEvent
- 5)
- // create a named window for the base class
- create window OrdersWindow.std:unique(name) as select * from ProductBaseEvent
- // The ServiceProductEvent class subclasses the ProductBaseEvent class
- insert into OrdersWindow select * from ServiceProductEvent
- 6)
- /**
- * interface InterfaceEvent {
- * public int getPrice();
- * public String getName();
- * }
- */
- // create a named window for the inteface
- create window InterfaceWindow.win: time(2 sec) as select * from InterfaceEvent
- // The InterfaceEventImpl is the implements for InterfaceEvent
- insert into InterfaceWindow select * from InterfaceEventImpl
从以上几个例子可以看得出,创建named window时用的事件类型只是用了该事件类型的属性定义,只要insert的事件列出了对应的属性名称就可以,当然属性的数据类型也得对应。如果属性名不对应,可以用as来重命名,就像例3和例4那样。第5个例子表明子类可以插入到父类定义的named window中。第六个例子表明实现类可以插入到用接口定义的named window中。
3.Selecting From Named Windows
这一节主要讲解如何查询named window中的事件。准确来说这并不是一种无条件的查询方式,监听器监听查询语句以后,必须发送对应的事件(创建window时指定的事件类型),然后先看是否满足named window的输出条件,再看是否满足查询语句的输出条件,所以并不是named window中的事件都会发给监听器。咱们先看一个例子:
- // first, you should create the AllOrdersNamedWindow
- create named window AllOrdersNamedWindow.win:length_batch(3) as OrderEvent
- select * from AllOrdersNamedWindow
这个select句子看似很简单,实际上并不是查询AllOrdersNamedWindow中的事件。实际过程是这样的:首先引擎检查AllOrdersNamedWindow中有多少事件,因为过期策略是length_batch(3),意思是当AllOrdersNamedWindow中包含3个事件,才会将这3个事件同时输出,然后再等待新的3个事件,然后再一起输出这3个事件。。。所以当输入某一个事件时,若不满足3个数量,则select语句不会返回任何内容。若满足3个数量,则监听select语句的监听器会得到AllOrdersNamedWindow中的最新的3各事件。
下面的几个句子都只有在length_batch(3)满足条件时才能有事件输出。
如果想查到上一次过期的3个事件,则查询语句改成下面的样子:
- select rstream * from AllOrdersNamedWindow
如果只想查询AllOrdernamedWindow里面的某几个属性,并且加上一些限制条件查看特定的事件,则查询语句改成下面的样子:
- select symbol, avg(price) from AllOrdersNamedWindow(sector='energy') group by symbol
因为上面所说的特点,所以查询语句可以在事件发送后再建立,也就是说我什么时候想查什么时候再建句子,named windows里有多少事件就如实返回多少。下面举个完整的例子总结一下:
- package example;
- import com.espertech.esper.client.EPAdministrator;
- import com.espertech.esper.client.EPRuntime;
- import com.espertech.esper.client.EPServiceProvider;
- import com.espertech.esper.client.EPServiceProviderManager;
- import com.espertech.esper.client.EPStatement;
- import com.espertech.esper.client.EventBean;
- import com.espertech.esper.client.UpdateListener;
- /**
- * Created by Luonanqin on 3/19/14.
- */
- class SelectEvent {
- private int price;
- private String name;
- public int getPrice() {
- return price;
- }
- public void setPrice(int price) {
- this.price = price;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- @Override
- public String toString() {
- return "name="+name+", price="+price;
- }
- }
- class SelectNamedWindowListener implements UpdateListener{
- public void update(EventBean[] newEvents, EventBean[] oldEvents) {
- if (newEvents != null) {
- System.out.println("There is "+newEvents.length+" events to be return!");
- for (int i = 0; i < newEvents.length;i++) {
- System.out.println(newEvents[i].getUnderlying());
- }
- }
- }
- }
- public class SelectNamedWindowTest{
- public static void main(String[] args) {
- EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider();
- EPAdministrator admin = epService.getEPAdministrator();
- EPRuntime runtime = epService.getEPRuntime();
- String selectEvent = SelectEvent.class.getName();
- String epl1 = "create window SelectNamedWindow.win:length_batch(3) as " + selectEvent;
- admin.createEPL(epl1);
- System.out.println("Create named window: create window SelectNamedWindow.win:length_batch(3) as "+selectEvent);
- String epl2 = "insert into SelectNamedWindow select * from " + selectEvent;
- admin.createEPL(epl2);
- SelectEvent se1 = new SelectEvent();
- se1.setName("se1");
- se1.setPrice(1);
- System.out.println("Send SelecEvent1 " + se1);
- runtime.sendEvent(se1);
- SelectEvent se2 = new SelectEvent();
- se2.setName("se2");
- se2.setPrice(2);
- System.out.println("Send SelecEvent2 " + se2);
- runtime.sendEvent(se2);
- // Can't create "select * from SelectamedWindow.win:time(3 sec)"
- String epl3 = "select * from SelectNamedWindow(price>=2)";
- EPStatement state3 = admin.createEPL(epl3);
- state3.addListener(new SelectNamedWindowListener());
- System.out.println("Register select sentence: select * from SelectNamedWindow(price>=2)");
- SelectEvent se3 = new SelectEvent();
- se3.setName("se3");
- se3.setPrice(3);
- System.out.println("Send SelecEvent3 " + se3 + "\n");
- runtime.sendEvent(se3);
- }
- }
执行结果:
- Create named window: create window SelectNamedWindow.win:length_batch(3) as example.SelectEvent
- Send SelecEvent1 name=se1, price=1
- Send SelecEvent2 name=se2, price=2
- Register select sentence: select * from SelectNamedWindow(price>=2)
- Send SelecEvent3 name=se3, price=3
- There is 2 events to be return!
- name=se2, price=2
- name=se3, price=3
上面的例子有一段注释“select * from SelectamedWindow.win:time(3 sec)”,实际上是因为win:time(3 sec)这个东西,之前create named window的时候,已经使用了一个win的view,所以这里就不能再使用win的view了。这个与view相关,就一笔带过了。另外还有一点,在select句子中的filter如果使用了variable,当变量的值在句子创建后改变了,引擎不会读取新的值,这个需要额外注意。
4.Triggered Select on Named Windows:On Select
上一节说到的查询方式实际上并不是很好用,而这一节就提供了一个非常简单的查询办法。他是通过发送一个触发事件即可得到当前window里有些什么事件,你还可以设置这个触发事件满足什么要求才可触发,或者这个触发事件和window中的事件达到某种关联后输出符合这个关联的事件或事件的部分属性。先来看看语法:
- on event_type[(filter_criteria)] [as stream_name]
- select select_list from window_name [as stream_name]
- [where criteria_expression] [group by grouping_expression_list] [having grouping_search_conditions] [order by order_by_expression_list]
event_type表示用来触发的事件,可以是任何一种事件类型,也可以是pattern(用来表达较为复杂的触发条件)。后面用括号括起来的包含了触发事件的限制条件,必须满足这个里面约定的条件才可用来触发查询。as stream_name为可选参数,主要用于具体的查询语句或者与window做关联用。select语句就不说了,和普通的没太大区别。后面的where条件限制了查询结果,满足结果的才可返回给监听器。group by、having、order by和之前说的用法一样,这里不做说明了。我们先来看几个简单的例子:
- // QueryEvent作为触发事件,查询OrderNamedWindow中的所有事件,并附带触发的事件作为结果返回(什么意思?)
- on QueryEvent select * from OrdersNamedWindow
- // QueryEvent作为触发事件,查询OrderNamedWindow中的所有事件作为结果返回(懂了吧)
- on QueryEvent select win.* from OrdersNamedWindow as win
- // volume大于0的QueryEvent作为触发事件,查询OrderNamedWindow中的事件,且事件的symbol要与QueryEvent的symbol一样,返回满足条件的window事件的symbol值,以及QueryEvent的symbol和volume值
- on QueryEvent(volume>0) as query
- select query.symbol, query.volume, win.symbol from OrdersNamedWindow as win
- where win.symbol = query.symbol
- // group by, having, order by的用法与前面所讲无差别,都是针对查询出来的事件
- on QueryEvent
- select symbol, sum(volume) from OrdersNamedWindow as win
- group by symbol having volume > 0 order by symbol
- // 每一次OrderNamedWindow有变化并满足限制条件即可触发监听器返回window中的事件。
- on OrdersNamedWindow as trig
- select onw.symbol, sum(onw.volume) from OrdersNamedWindow as onw
- where onw.symbol = trig.symbol
前两个例子我相信大家已经明白了。如果select子句里是*,则返回的不仅仅是window中的事件,还会返回触发查询的事件,并且返回的多行结果中每行都会包含这个触发事件。第三个例子可以看出as的用法。最后一个例子有些特别,触发的事件就是named window本身,目的就是为了named window变化了就能返回变化后的结果。但是这里的“变化”不是简单的事件有增加或者减少,而是指named window定义时指定的view达到触发条件有输出了,你才能真的看到查询结果。下面列一个完整的例子来概括一下上面说到的几点内容:
- package example;
- import com.espertech.esper.client.EPAdministrator;
- import com.espertech.esper.client.EPRuntime;
- import com.espertech.esper.client.EPServiceProvider;
- import com.espertech.esper.client.EPServiceProviderManager;
- import com.espertech.esper.client.EPStatement;
- import com.espertech.esper.client.EventBean;
- import com.espertech.esper.client.UpdateListener;
- /**
- * Created by Luonanqin on 3/29/14.
- */
- class OnSelectTrigger {
- private int trigger;
- public int getTrigger() {
- return trigger;
- }
- public void setTrigger(int trigger) {
- this.trigger = trigger;
- }
- public String toString() {
- return "trigger=" + trigger;
- }
- }
- class OnSelectEvent {
- private String name;
- private int size;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getSize() {
- return size;
- }
- public void setSize(int size) {
- this.size = size;
- }
- public String toString() {
- return "name=" + name + ", size=" + size;
- }
- }
- class OnSelectWindowListener implements UpdateListener {
- public void update(EventBean[] newEvents, EventBean[] oldEvents) {
- if (newEvents != null) {
- System.out.println("Trigger On Select:");
- System.out.println("There is " + newEvents.length + " OnSelectEvent in OnSelectWindow!");
- for (int i = 0; i < newEvents.length; i++) {
- System.out.println(newEvents[i].getUnderlying());
- }
- }
- }
- }
- public class OnSelectWindowTest {
- public static void main(String[] args) {
- EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider();
- EPAdministrator admin = epService.getEPAdministrator();
- EPRuntime runtime = epService.getEPRuntime();
- String triggerEvent = OnSelectTrigger.class.getName();
- String selectEvent = OnSelectEvent.class.getName();
- // win:keepall()使named window中的事件一直保留
- // String epl1 = "create window OnSelectWindow.win:keepall() as select * from " + selectEvent;
- String epl1 = "create window OnSelectWindow.win:length(2) as select * from " + selectEvent;
- String epl2 = "insert into OnSelectWindow select * from " + selectEvent;
- String epl3 = "on " + triggerEvent + "(trigger>=2) select osw.* from OnSelectWindow as osw";
- System.out.println("Create Window:" + epl1);
- System.out.println("Trigger sentence: " + epl3);
- System.out.println();
- admin.createEPL(epl1);
- admin.createEPL(epl2);
- EPStatement state3 = admin.createEPL(epl3);
- state3.addListener(new OnSelectWindowListener());
- OnSelectEvent ose1 = new OnSelectEvent();
- ose1.setName("ose1");
- ose1.setSize(1);
- runtime.sendEvent(ose1);
- System.out.println("Send OnSelectEvent 1: " + ose1);
- OnSelectEvent ose2 = new OnSelectEvent();
- ose2.setName("ose2");
- ose2.setSize(2);
- runtime.sendEvent(ose2);
- System.out.println("Send OnSelectEvent 2: " + ose2);
- OnSelectEvent ose3 = new OnSelectEvent();
- ose3.setName("ose3");
- ose3.setSize(3);
- runtime.sendEvent(ose3);
- System.out.println("Send OnSelectEvent 3: " + ose3);
- OnSelectTrigger ost1 = new OnSelectTrigger();
- ost1.setTrigger(1);
- System.out.println("Send OnSelectTrigger " + ost1);
- runtime.sendEvent(ost1);
- OnSelectTrigger ost2 = new OnSelectTrigger();
- ost2.setTrigger(2);
- System.out.println("Send OnSelectTrigger " + ost2 + "\n");
- runtime.sendEvent(ost2);
- System.out.println();
- String epl4 = "on OnSelectWindow select osw.* from OnSelectWindow as osw";
- EPStatement state4 = admin.createEPL(epl4);
- state4.addListener(new OnSelectWindowListener());
- System.out.println("Trigger sentence: " + epl4 + "\n");
- OnSelectEvent ose4 = new OnSelectEvent();
- ose4.setName("ose4");
- ose4.setSize(4);
- System.out.println("Send OnSelectEvent 4(also a Trigger): " + ose4 + "\n");
- runtime.sendEvent(ose4);
- System.out.println();
- OnSelectEvent ose5 = new OnSelectEvent();
- ose5.setName("ose5");
- ose5.setSize(5);
- System.out.println("Send OnSelectEvent 5(also a Trigger): " + ose5 + "\n");
- runtime.sendEvent(ose5);
- }
- }
执行结果:
- Create Window:create window OnSelectWindow.win:length(2) as select * from example.OnSelectEvent
- Trigger sentence: on example.OnSelectTrigger(trigger>=2) select osw.* from OnSelectWindow as osw
- Send OnSelectEvent 1: name=ose1, size=1
- Send OnSelectEvent 2: name=ose2, size=2
- Send OnSelectEvent 3: name=ose3, size=3
- Send OnSelectTrigger trigger=1
- Send OnSelectTrigger trigger=2
- Trigger On Select:
- There is 2 OnSelectEvent in OnSelectWindow!
- name=ose2, size=2
- name=ose3, size=3
- Trigger sentence: on OnSelectWindow select osw.* from OnSelectWindow as osw
- Send OnSelectEvent 4(also a Trigger): name=ose4, size=4
- Trigger On Select:
- There is 2 OnSelectEvent in OnSelectWindow!
- name=ose3, size=3
- name=ose4, size=4
- Send OnSelectEvent 5(also a Trigger): name=ose5, size=5
- Trigger On Select:
- There is 2 OnSelectEvent in OnSelectWindow!
- name=ose4, size=4
- name=ose5, size=5
5.Triggered Delete on Named Windows:On Delete
除了可以用on select语句查询named window,还可以用on delete语句删除named window中的事件。语法和on select基本一样,同样能够设置一定条件限制触发事件,以及删除符合特定条件的事件。语法如下:
- on event_type[(filter_criteria)] [as stream_name] delete from window_name [as stream_name]
- [where criteria_expression]
和on select不同的是,delete后面不跟属性什么的,因为删除的就是事件,不存在删除事件中的某些属性这种情况。filter_criteria用来限制触发事件,where criteria_expression用来限制要删除的事件。而且没有group by, having, Order by。举例如下:
- package example;
- import com.espertech.esper.client.EPAdministrator;
- import com.espertech.esper.client.EPRuntime;
- import com.espertech.esper.client.EPServiceProvider;
- import com.espertech.esper.client.EPServiceProviderManager;
- import com.espertech.esper.client.EPStatement;
- import com.espertech.esper.client.EventBean;
- import com.espertech.esper.client.UpdateListener;
- /**
- * Created by Luonanqin on 3/30/14.
- */
- class OnDeleteTrigger {
- private int trigger;
- public int getTrigger() {
- return trigger;
- }
- public void setTrigger(int trigger) {
- this.trigger = trigger;
- }
- public String toString() {
- return "trigger=" + trigger;
- }
- }
- class OnDeleteEvent {
- private String name;
- private int size;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getSize() {
- return size;
- }
- public void setSize(int size) {
- this.size = size;
- }
- public String toString() {
- return "name=" + name + ", size=" + size;
- }
- }
- class OnDeleteWindowListener implements UpdateListener {
- public void update(EventBean[] newEvents, EventBean[] oldEvents) {
- if (newEvents != null) {
- System.out.println();
- System.out.println("Trigger On Delete:");
- System.out.println("There is " + newEvents.length + " OnDeleteEvent to be deleted in OnDeleteWindow!");
- for (int i = 0; i < newEvents.length; i++) {
- System.out.println(newEvents[i].getUnderlying());
- }
- }
- }
- }
- class OnSelectListener implements UpdateListener{
- public void update(EventBean[] newEvents, EventBean[] oldEvents) {
- if (newEvents != null) {
- System.out.println();
- System.out.println("Trigger On Select:");
- System.out.println("There is " + newEvents.length + " OnDeleteEvent in OnDeleteWindow!");
- for (int i = 0; i < newEvents.length; i++) {
- System.out.println(newEvents[i].getUnderlying());
- }
- }
- }
- }
- public class OnDeleteWindowTest {
- public static void main(String[] args) {
- EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider();
- EPAdministrator admin = epService.getEPAdministrator();
- EPRuntime runtime = epService.getEPRuntime();
- String triggerEvent = OnDeleteTrigger.class.getName();
- String deleteEvent = OnDeleteEvent.class.getName();
- String epl1 = "create window OnDeleteWindow.win:keepall() as select * from " + deleteEvent;
- String epl2 = "insert into OnDeleteWindow select * from " + deleteEvent;
- String epl3 = "on " + triggerEvent + "(trigger>0) as odt delete from OnDeleteWindow as odw where odt.trigger=odw.size";
- String epl4 = "on " + triggerEvent + "(trigger=0) select odw.* from OnDeleteWindow as odw";
- System.out.println("Create Window: " + epl1);
- System.out.println("Delete Trigger: " + epl3);
- System.out.println("Select Trigger: " + epl4);
- System.out.println();
- admin.createEPL(epl1);
- admin.createEPL(epl2);
- EPStatement state3 = admin.createEPL(epl3);
- state3.addListener(new OnDeleteWindowListener());
- EPStatement state4 = admin.createEPL(epl4);
- state4.addListener(new OnSelectListener());
- OnDeleteEvent ose1 = new OnDeleteEvent();
- ose1.setName("ose1");
- ose1.setSize(1);
- runtime.sendEvent(ose1);
- System.out.println("Send OnDeleteEvent 1: " + ose1);
- OnDeleteEvent ose2 = new OnDeleteEvent();
- ose2.setName("ose2");
- ose2.setSize(2);
- runtime.sendEvent(ose2);
- System.out.println("Send OnDeleteEvent 2: " + ose2);
- OnDeleteEvent ose3 = new OnDeleteEvent();
- ose3.setName("ose3");
- ose3.setSize(3);
- runtime.sendEvent(ose3);
- System.out.println("Send OnDeleteEvent 3: " + ose3);
- OnDeleteTrigger ost1 = new OnDeleteTrigger();
- ost1.setTrigger(0);
- System.out.println("\nSend OnSelectTrigger " + ost1);
- runtime.sendEvent(ost1);
- OnDeleteTrigger ost2 = new OnDeleteTrigger();
- ost2.setTrigger(2);
- System.out.println("\nSend OnDeleteTrigger " + ost2);
- runtime.sendEvent(ost2);
- OnDeleteTrigger ost3 = new OnDeleteTrigger();
- ost3.setTrigger(0);
- System.out.println("\nSend OnSelectTrigger " + ost3);
- runtime.sendEvent(ost3);
- }
- }
执行结果:
- Create Window: create window OnDeleteWindow.win:keepall() as select * from example.OnDeleteEvent
- Delete Trigger: on example.OnDeleteTrigger(trigger>0) as odt delete from OnDeleteWindow as odw where odt.trigger=odw.size
- Select Trigger: on example.OnDeleteTrigger(trigger=0) select odw.* from OnDeleteWindow as odw
- Send OnDeleteEvent 1: name=ose1, size=1
- Send OnDeleteEvent 2: name=ose2, size=2
- Send OnDeleteEvent 3: name=ose3, size=3
- Send OnSelectTrigger trigger=0
- Trigger On Select:
- There is 3 OnDeleteEvent in OnDeleteWindow!
- name=ose1, size=1
- name=ose2, size=2
- name=ose3, size=3
- Send OnDeleteTrigger trigger=2
- Trigger On Delete:
- There is 1 OnDeleteEvent to be deleted in OnDeleteWindow!
- name=ose2, size=2
- Send OnSelectTrigger trigger=0
- Trigger On Select:
- There is 2 OnDeleteEvent in OnDeleteWindow!
- name=ose1, size=1
- name=ose3, size=3
6.Triggered Select+Delete on Named Windows: the On Select Delete
如果我们想在从named window查询出结果的同时删掉查询结果,那么可以使用on select and delete语句。语法和on select语句几乎是一样的,只是多了个delete。语法如下:
- on trigger
- select [and] delete select_list...
- ... (please see on-select for from, group by, having, order by)...
直接上一个完整例子:
- package example;
- import com.espertech.esper.client.EPAdministrator;
- import com.espertech.esper.client.EPRuntime;
- import com.espertech.esper.client.EPServiceProvider;
- import com.espertech.esper.client.EPServiceProviderManager;
- import com.espertech.esper.client.EPStatement;
- import com.espertech.esper.client.EventBean;
- import com.espertech.esper.client.UpdateListener;
- /**
- * Created by Luonanqin on 3/29/14.
- */
- class OnSelectDeleteTrigger {
- private int trigger;
- public int getTrigger() {
- return trigger;
- }
- public void setTrigger(int trigger) {
- this.trigger = trigger;
- }
- public String toString() {
- return "trigger=" + trigger;
- }
- }
- class OnSelectDeleteEvent {
- private String name;
- private int size;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getSize() {
- return size;
- }
- public void setSize(int size) {
- this.size = size;
- }
- public String toString() {
- return "name=" + name + ", size=" + size;
- }
- }
- class OnSelectDeleteWindowListener implements UpdateListener {
- public void update(EventBean[] newEvents, EventBean[] oldEvents) {
- if (newEvents != null) {
- System.out.println();
- System.out.println("Trigger On Select and Delete:");
- System.out.println("There is " + newEvents.length + " OnSelectDeleteEvent in OnSelectDeleteWindow!");
- for (int i = 0; i < newEvents.length; i++) {
- System.out.println(newEvents[i].getUnderlying());
- }
- }
- }
- }
- public class OnSelectDeleteWindowTest {
- public static void main(String[] args) {
- EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider();
- EPAdministrator admin = epService.getEPAdministrator();
- EPRuntime runtime = epService.getEPRuntime();
- String triggerEvent = OnSelectDeleteTrigger.class.getName();
- String selectDeleteEvent = OnSelectDeleteEvent.class.getName();
- String epl1 = "create window OnSelectDeleteWindow.win:keepall() as select * from " + selectDeleteEvent;
- String epl2 = "insert into OnSelectDeleteWindow select * from " + selectDeleteEvent;
- String epl3 = "on " + triggerEvent + " select and delete osw.* from OnSelectDeleteWindow as osw";
- System.out.println("Create Window: " + epl1);
- System.out.println("Select and Delete Trigger: " + epl3);
- System.out.println();
- admin.createEPL(epl1);
- admin.createEPL(epl2);
- EPStatement state3 = admin.createEPL(epl3);
- state3.addListener(new OnSelectDeleteWindowListener());
- OnSelectDeleteEvent osde1 = new OnSelectDeleteEvent();
- osde1.setName("osde1");
- osde1.setSize(1);
- runtime.sendEvent(osde1);
- System.out.println("Send OnSelectDeleteEvent 1: " + osde1);
- OnSelectDeleteEvent osde2 = new OnSelectDeleteEvent();
- osde2.setName("osde2");
- osde2.setSize(2);
- runtime.sendEvent(osde2);
- System.out.println("Send OnSelectDeleteEvent 2: " + osde2);
- OnSelectDeleteEvent osde3 = new OnSelectDeleteEvent();
- osde3.setName("osde3");
- osde3.setSize(3);
- runtime.sendEvent(osde3);
- System.out.println("Send OnSelectDeleteEvent 3: " + osde3);
- OnSelectDeleteTrigger osdt1 = new OnSelectDeleteTrigger();
- osdt1.setTrigger(1);
- System.out.println("Send OnSelectDeleteTrigger " + osdt1);
- runtime.sendEvent(osdt1);
- System.out.println();
- OnSelectDeleteEvent osde4 = new OnSelectDeleteEvent();
- osde4.setName("osde4");
- osde4.setSize(4);
- System.out.println("Send OnSelectDeleteEvent 4: " + osde4);
- runtime.sendEvent(osde4);
- OnSelectDeleteTrigger osdt2 = new OnSelectDeleteTrigger();
- osdt2.setTrigger(1);
- System.out.println("Send OnSelectDeleteTrigger " + osdt2);
- runtime.sendEvent(osdt2);
- }
- }
执行结果:
- Create Window: create window OnSelectDeleteWindow.win:keepall() as select * from example.OnSelectDeleteEvent
- Select and Delete Trigger: on example.OnSelectDeleteTrigger select and delete osw.* from OnSelectDeleteWindow as osw
- Send OnSelectDeleteEvent 1: name=osde1, size=1
- Send OnSelectDeleteEvent 2: name=osde2, size=2
- Send OnSelectDeleteEvent 3: name=osde3, size=3
- Send OnSelectDeleteTrigger trigger=1
- Trigger On Select and Delete:
- There is 3 OnSelectDeleteEvent in OnSelectDeleteWindow!
- name=osde1, size=1
- name=osde2, size=2
- name=osde3, size=3
- Send OnSelectDeleteEvent 4: name=osde4, size=4
- Send OnSelectDeleteTrigger trigger=1
- Trigger On Select and Delete:
- There is 1 OnSelectDeleteEvent in OnSelectDeleteWindow!
- name=osde4, size=4
7.Updating Named Windows: the On Update clause
除了查询和删除window里的事件,我们还可以更新事件,而且同样也是通过发送一个特定事件来出发更新操作。语法如下:
- on event_type[(filter_criteria)] [as stream_name]
- update window_name [as stream_name]
- set property_name = expression [, property_name = expression [,...]] [where criteria_expression]
filter_criteria用来过滤触发事件,criteria_expression用来过滤window中的事件不予更改。和sql类似,set后面跟着要修改的属性及要赋的值,多个属性名值对用逗号分隔。先看一个简单的例子:
- on NewOrderEvent(volume>0) as myNewOrders
- update AllOrdersNamedWindow as myNamedWindow set price = myNewOrders.price
- where myNamedWindow.symbol = myNewOrders.symbol
我想不用做太多解释大家就能很容易看懂。不过下面这个例子呢:
- on UpdateEvent as upd
- update MyWindow as win
- set field_a = 1,
- field_b = win.field_a, // assigns the value 1
- field_c = initial.field_a // assigns the field_a original value before update
上面的例子中,field_a被更新为1,然后用修改后的field_a赋值给field_b,那么field_b实际上也变成1了。但是如果想用更新前的field_a的值赋给field_c,那么就要写成initial.field_a。initial是关键字,所以不能省略。
我们可以用监听器监听on update语句,返回给监听器的就是被更新的事件。结合上面的两点内容,我们来看一个完整的例子:
- package example;
- import com.espertech.esper.client.EPAdministrator;
- import com.espertech.esper.client.EPRuntime;
- import com.espertech.esper.client.EPServiceProvider;
- import com.espertech.esper.client.EPServiceProviderManager;
- import com.espertech.esper.client.EPStatement;
- import com.espertech.esper.client.EventBean;
- import com.espertech.esper.client.UpdateListener;
- import java.io.Serializable;
- /**
- * Created by Luonanqin on 4/5/14.
- */
- class OnUpdateTrigger {
- private int trigger;
- public int getTrigger() {
- return trigger;
- }
- public void setTrigger(int trigger) {
- this.trigger = trigger;
- }
- public String toString() {
- return "trigger=" + trigger;
- }
- }
- class OnUpdateEvent implements Serializable{
- private String name;
- private int size;
- private int price;
- public int getPrice() {
- return price;
- }
- public void setPrice(int price) {
- this.price = price;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getSize() {
- return size;
- }
- public void setSize(int size) {
- this.size = size;
- }
- public String toString() {
- return "name=" + name + ", size=" + size + ", price=" + price;
- }
- }
- class OnUpdateWindowListener implements UpdateListener {
- public void update(EventBean[] newEvents, EventBean[] oldEvents) {
- if (newEvents != null) {
- System.out.println();
- System.out.println("Trigger On Update:");
- System.out.println("There is " + newEvents.length + " to be updated in OnUpdateWindow!");
- for (int i = 0; i < newEvents.length; i++) {
- System.out.println(newEvents[i].getUnderlying());
- }
- }
- }
- }
- class OnUpdateSelectWindowListener implements UpdateListener {
- public void update(EventBean[] newEvents, EventBean[] oldEvents) {
- if (newEvents != null) {
- System.out.println();
- System.out.println("Trigger On Select:");
- System.out.println("There is " + newEvents.length + " OnUpdateEvent in OnUpdateWindow!");
- for (int i = 0; i < newEvents.length; i++) {
- System.out.println(newEvents[i].getUnderlying());
- }
- }
- }
- }
- public class OnUpdateWindowTest {
- public static void main(String[] args) {
- EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider();
- EPAdministrator admin = epService.getEPAdministrator();
- EPRuntime runtime = epService.getEPRuntime();
- String triggerEvent = OnUpdateTrigger.class.getName();
- String updateEvent = OnUpdateEvent.class.getName();
- String epl1 = "create window OnUpdateWindow.win:keepall() as select * from " + updateEvent;
- String epl2 = "insert into OnUpdateWindow select * from " + updateEvent;
- String epl3 = "on " + triggerEvent + "(trigger>0) as out update OnUpdateWindow as ouw set size=out.trigger, price=initial.size where out.trigger<ouw.price";
- String epl4 = "on " + triggerEvent + "(trigger=0) select ouw.* from OnUpdateWindow as ouw";
- System.out.println("Create Window: " + epl1);
- System.out.println("Update Trigger sentence: " + epl3);
- System.out.println();
- admin.createEPL(epl1);
- admin.createEPL(epl2);
- EPStatement state3 = admin.createEPL(epl3);
- state3.addListener(new OnUpdateWindowListener());
- EPStatement state4 = admin.createEPL(epl4);
- state4.addListener(new OnUpdateSelectWindowListener());
- OnUpdateEvent oue1 = new OnUpdateEvent();
- oue1.setName("oue1");
- oue1.setSize(1);
- oue1.setPrice(2);
- runtime.sendEvent(oue1);
- System.out.println("Send OnUpdateEvent 1: " + oue1);
- OnUpdateEvent oue2 = new OnUpdateEvent();
- oue2.setName("oue2");
- oue2.setSize(2);
- oue2.setPrice(3);
- runtime.sendEvent(oue2);
- System.out.println("Send OnUpdateEvent 2: " + oue2);
- OnUpdateEvent oue3 = new OnUpdateEvent();
- oue3.setName("oue3");
- oue3.setSize(3);
- oue3.setPrice(4);
- runtime.sendEvent(oue3);
- System.out.println("Send OnUpdateEvent 3: " + oue3);
- OnUpdateTrigger ost1 = new OnUpdateTrigger();
- ost1.setTrigger(0);
- System.out.println("\nSend OnUpdateTrigger " + ost1);
- runtime.sendEvent(ost1);
- OnUpdateTrigger ost2 = new OnUpdateTrigger();
- ost2.setTrigger(2);
- System.out.println("\nSend OnUpdateTrigger " + ost2);
- runtime.sendEvent(ost2);
- OnUpdateTrigger ost3 = new OnUpdateTrigger();
- ost3.setTrigger(0);
- System.out.println("\nSend OnUpdateTrigger " + ost3);
- runtime.sendEvent(ost3);
- }
- }
执行结果:
- Create Window: create window OnUpdateWindow.win:keepall() as select * from example.OnUpdateEvent
- Update Trigger sentence: on example.OnUpdateTrigger(trigger>0) as out update OnUpdateWindow as ouw set size=out.trigger, price=initial.size where out.trigger<ouw.price
- Send OnUpdateEvent 1: name=oue1, size=1, price=2
- Send OnUpdateEvent 2: name=oue2, size=2, price=3
- Send OnUpdateEvent 3: name=oue3, size=3, price=4
- Send OnUpdateTrigger trigger=0
- Trigger On Select:
- There is 3 OnUpdateEvent in OnUpdateWindow!
- name=oue1, size=1, price=2
- name=oue2, size=2, price=3
- name=oue3, size=3, price=4
- Send OnUpdateTrigger trigger=2
- Trigger On Update:
- There is 2 to be updated in OnUpdateWindow!
- name=oue2, size=2, price=2
- name=oue3, size=2, price=3
- Send OnUpdateTrigger trigger=0
- Trigger On Select:
- There is 3 OnUpdateEvent in OnUpdateWindow!
- name=oue1, size=1, price=2
- name=oue2, size=2, price=2
- name=oue3, size=2, price=3
OnUpdateEvent和平时我们定义的事件不太一样,它实现了Serializable接口。这是因为update更新属性前会复制一份同样的事件暂存,比如initial这种操作就需要更新前的值,所以就需要我们实现序列化接口。如果不想通过代码完成这个序列化要求,也可以通过配置完成,这个就不在这里说了。另外还有以下几点需要注意:
a)需要更新的属性一定要是可写的
b)XML格式的事件不能通过此语句更新
c)嵌套属性不支持更新
8.Triggered Upsert using the On-Merge Clause
除了上面的on select,on update,on delete操作,esper还支持on merge操作。他可以在满足不同条件的情况下完成对应的window中的事件的insert,update和delete操作,所以语法相对前面几种就复杂很多。语法如下:
- on event_type[(filter_criteria)] [as stream_name] merge [into] window_name [as stream_name]
- [where criteria_expression]
- when [not] matched [and search_condition] then [
- insert [into streamname] [ (property_name [, property_name] [,...]) ]
- select select_expression [, select_expression[,...]] [where filter_expression]
- |
- update set property_name = expression [, property_name = expression [,...]] [where filter_expression]
- |
- delete [where filter_expression]
- ]
- [then [insert|update|delete]] [,then ...]
- [when ... then ... [...]]
a.第一行就不多说了,和前面的用法都一样。
b.第二行的where语句将事件分为了matched(满足where条件)和not matched(不满足where条件)两类
c.第三行的when配合matched或者not matched表示“window中满足where条件的事件,执行下面的操作/window中不满足where条件的事件,执行下面的操作”。search_condition为可选字段,表示再次过滤matched或not matched中的事件,只有没被过滤掉的事件才可以被then后面的语句操作。
d.第四行的insert语句和之前说的insert into不太一样。虽然都表示插入事件,但是由于into streamname是可选,所以在只有insert关键字的情况下,会将触发的事件插入到当前的named window中。如果要指明插入到别的named window中就要在insert之后带上into及window的名字。再之后的圆括号中的内容表示要插入的事件的属性,一般情况是在将事件插入到别的window中时,用它来重命名第五行中列出的属性。
e.第五行实际是配合第四行一起使用的。select子句不可少,不然引擎就不知道要往window中插入什么内容了。select的内容可以是*,也可以是属性列表。where语句再一次限制可插入的触发事件。注意select后面没有from,因为事件来源就是当时的触发事件。
f.第七行用来更新符合条件的事件,可更新单个或多个属性,where条件判断是否可进行更新操作。
g.第九行用来删除符合条件的事件,只包含关键字delete以及可选的where语句。
h.最后两行表示on merge中可以有多个when,每个when可以有多个then及insert或updata或delete语句,这样就能组成一个非常复杂的merge操作了。
语法内容有点多,但是应该都还容易理解吧。除了语法,还有几点需要注意的:
1. when not matched后面只能跟insert语句,而when matched则没有任何限制。
2. select语句中不能使用聚合函数。
3. 当某一个when matched或者no matched和其search_condition满足,则这个when下的所有then都会执行,并且按照顺序执行。
4. 避免在一个when中同时使用update和delete,esper不能保证两个都有效执行。
接下来我给大家一个完整的例子,各位可以好好揣摩一下上面所讲的要点。
- package example;
- import com.espertech.esper.client.EPAdministrator;
- import com.espertech.esper.client.EPRuntime;
- import com.espertech.esper.client.EPServiceProvider;
- import com.espertech.esper.client.EPServiceProviderManager;
- import com.espertech.esper.client.EPStatement;
- import com.espertech.esper.client.EventBean;
- import com.espertech.esper.client.UpdateListener;
- import java.io.Serializable;
- import java.util.HashMap;
- import java.util.Map;
- /**
- * Created by Luonanqin on 4/8/14.
- */
- class MergeEvent implements Serializable {
- private int mergeId;
- private String mergeStr;
- private int mergeSize;
- private boolean deleteFlag;
- public int getMergeId() {
- return mergeId;
- }
- public void setMergeId(int mergeId) {
- this.mergeId = mergeId;
- }
- public String getMergeStr() {
- return mergeStr;
- }
- public void setMergeStr(String mergeStr) {
- this.mergeStr = mergeStr;
- }
- public int getMergeSize() {
- return mergeSize;
- }
- public void setMergeSize(int mergeSize) {
- this.mergeSize = mergeSize;
- }
- public boolean isDeleteFlag() {
- return deleteFlag;
- }
- public void setDeleteFlag(boolean deleteFlag) {
- this.deleteFlag = deleteFlag;
- }
- public String toString() {
- return "mergeId=" + mergeId + ", mergeStr=" + mergeStr + ", mergeSize=" + mergeSize + ", deleteFlag=" + deleteFlag;
- }
- }
- class OnMergeWindowlistener implements UpdateListener {
- public void update(EventBean[] newEvents, EventBean[] oldEvents) {
- if (newEvents != null) {
- System.out.println("Trigger MergeWindow:");
- for (int i = 0; i < newEvents.length; i++) {
- System.out.println(newEvents[i].getUnderlying());
- }
- }
- }
- }
- class SelectLogWindowlistener implements UpdateListener {
- public void update(EventBean[] newEvents, EventBean[] oldEvents) {
- if (newEvents != null) {
- for (int i = 0; i < newEvents.length; i++) {
- System.out.println(newEvents[i].getUnderlying());
- }
- }
- }
- }
- class SelectMergeWindowlistener implements UpdateListener {
- public void update(EventBean[] newEvents, EventBean[] oldEvents) {
- if (newEvents != null) {
- for (int i = 0; i < newEvents.length; i++) {
- System.out.println(newEvents[i].getUnderlying());
- }
- }
- }
- }
- public class OnMergeWindowTest {
- public static void main(String[] args) {
- EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider();
- EPAdministrator admin = epService.getEPAdministrator();
- EPRuntime runtime = epService.getEPRuntime();
- String mergeEvent = MergeEvent.class.getName();
- String epl1 = "create window MergeWindow.win:keepall() select * from " + mergeEvent;
- String epl2 = "create schema LogEvent as (id int, name string)";
- String epl3 = "create window LogWindow.win:keepall() as LogEvent";
- String epl4 = "on " + mergeEvent + "(mergeSize > 0) me merge MergeWindow mw where me.mergeId = mw.mergeId "
- + "when matched and me.deleteFlag = true then delete "
- + "when matched then update set mergeSize = mergeSize + me.mergeSize where mw.mergeSize > 3 "
- // MergeWindow中不存在的事件都会在触发merge时插入到window中,同时将部分属性插入到LogWindow中用于记录
- + "when not matched then insert select * then insert into LogWindow(id, name) select me.mergeId, me.mergeStr";
- String epl5 = "on LogEvent(id=0) select lw.* from LogWindow as lw";
- String epl6 = "on " + mergeEvent + "(mergeSize = 0) select mw.* from MergeWindow as mw";
- System.out.println("Create Window: " + epl1);
- System.out.println("Merge Trigger: " + epl4);
- System.out.println();
- admin.createEPL(epl1);
- admin.createEPL(epl2);
- admin.createEPL(epl3);
- EPStatement state1 = admin.createEPL(epl4);
- state1.addListener(new OnMergeWindowlistener());
- EPStatement state2 = admin.createEPL(epl5);
- state2.addListener(new SelectLogWindowlistener());
- EPStatement state3 = admin.createEPL(epl6);
- state3.addListener(new SelectMergeWindowlistener());
- Map<String, Object> selectLog = new HashMap<String, Object>();
- selectLog.put("id", 0);
- MergeEvent selectMerge = new MergeEvent();
- selectMerge.setMergeSize(0);
- MergeEvent me1 = new MergeEvent();
- me1.setDeleteFlag(false);
- me1.setMergeId(1);
- me1.setMergeSize(2);
- me1.setMergeStr("me1");
- System.out.println("Send MergeEvent 1: " + me1);
- runtime.sendEvent(me1);
- MergeEvent me2 = new MergeEvent();
- me2.setDeleteFlag(false);
- me2.setMergeId(2);
- me2.setMergeSize(3);
- me2.setMergeStr("me2");
- System.out.println("Send MergeEvent 2: " + me2);
- runtime.sendEvent(me2);
- MergeEvent me3 = new MergeEvent();
- me3.setDeleteFlag(false);
- me3.setMergeId(3);
- me3.setMergeSize(4);
- me3.setMergeStr("me3");
- System.out.println("Send MergeEvent 3: " + me3);
- runtime.sendEvent(me3);
- /**
- * 查询之前插入的三个事件
- */
- System.out.println("\nSend MergeEvent to Select MergeWindow!");
- runtime.sendEvent(selectMerge);
- /**
- * 查询LogWindow中记录的MergeEvent部分属性
- */
- System.out.println("\nSend LogEvent to Select LogWindow!");
- runtime.sendEvent(selectLog, "LogEvent");
- /**
- * 因为mergeId是3,所以MergeWindow中只有mergeId=3的事件有资格被更新。
- * 并且mergeSize>3,所以可以执行更新操作。
- */
- MergeEvent me4 = new MergeEvent();
- me4.setDeleteFlag(false);
- me4.setMergeId(3);
- me4.setMergeSize(5);
- me4.setMergeStr("me4");
- System.out.println("\nSend MergeEvent 4: " + me4);
- runtime.sendEvent(me4);
- System.out.println("\nSend MergeEvent to Select MergeWindow!");
- runtime.sendEvent(selectMerge);
- /**
- * 因为mergeId是1,所以MergeWindow中只有mergeId=1的事件有资格被更新。
- * 并且deleteFlag=true,所以mergeId=1的事件将从MergeWindow中移除
- */
- MergeEvent me5 = new MergeEvent();
- me5.setDeleteFlag(true);
- me5.setMergeId(1);
- me5.setMergeSize(6);
- me5.setMergeStr("me5");
- System.out.println("\nSend MergeEvent 5: " + me5);
- runtime.sendEvent(me5);
- System.out.println("\nSend MergeEvent to Select MergeWindow!");
- runtime.sendEvent(selectMerge);
- }
- }
执行结果:
- Create Window: create window MergeWindow.win:keepall() select * from example.MergeEvent
- Merge Trigger: on example.MergeEvent(mergeSize > 0) me merge MergeWindow mw where me.mergeId = mw.mergeId when matched and me.deleteFlag = true then delete when matched then update set mergeSize = mergeSize + me.mergeSize where mw.mergeSize > 3 when not matched then insert select * then insert into LogWindow(id, name) select me.mergeId, me.mergeStr
- Send MergeEvent 1: mergeId=1, mergeStr=me1, mergeSize=2, deleteFlag=false
- Trigger MergeWindow:
- mergeId=1, mergeStr=me1, mergeSize=2, deleteFlag=false
- Send MergeEvent 2: mergeId=2, mergeStr=me2, mergeSize=3, deleteFlag=false
- Trigger MergeWindow:
- mergeId=2, mergeStr=me2, mergeSize=3, deleteFlag=false
- Send MergeEvent 3: mergeId=3, mergeStr=me3, mergeSize=4, deleteFlag=false
- Trigger MergeWindow:
- mergeId=3, mergeStr=me3, mergeSize=4, deleteFlag=false
- Send MergeEvent to Select MergeWindow!
- mergeId=1, mergeStr=me1, mergeSize=2, deleteFlag=false
- mergeId=2, mergeStr=me2, mergeSize=3, deleteFlag=false
- mergeId=3, mergeStr=me3, mergeSize=4, deleteFlag=false
- Send LogEvent to Select LogWindow!
- {id=1, name=me1}
- {id=2, name=me2}
- {id=3, name=me3}
- Send MergeEvent 4: mergeId=3, mergeStr=me4, mergeSize=5, deleteFlag=false
- Trigger MergeWindow:
- mergeId=3, mergeStr=me3, mergeSize=9, deleteFlag=false
- Send MergeEvent to Select MergeWindow!
- mergeId=1, mergeStr=me1, mergeSize=2, deleteFlag=false
- mergeId=2, mergeStr=me2, mergeSize=3, deleteFlag=false
- mergeId=3, mergeStr=me3, mergeSize=9, deleteFlag=false
- Send MergeEvent 5: mergeId=1, mergeStr=me5, mergeSize=6, deleteFlag=true
- Send MergeEvent to Select MergeWindow!
- mergeId=2, mergeStr=me2, mergeSize=3, deleteFlag=false
- mergeId=3, mergeStr=me3, mergeSize=9, deleteFlag=false
9.Selecting/Updating/Deleting From Named Windows Using Fire-And-Forget Queries
上面对于named window的所有操作,都是要发送一个事件到引擎才可达到目的。那是否可以不发送事件直接执行select/update/delete语句达到目的呢?Esper确实为大家提供了一种简单的方式来操作named window。和之前说的有很大的不同,首先不需要发送任何事件到引擎即可select/update/delete,其次不需要监听器就可立即获得操作结果。4.9版本只支持这三种操作,不过现在的4.11已经增加了很多别的操作,详细内容请各位自己去看官方文档吧。由于本节内容较为简单,所以我直接给大家展示语法及一个完整的例子。
- // select
- select *[, property_name[,...]] from window_name [where criteria_expression] [oder by] [having] [subquery]
- // update 子查询,聚合函数等不能用于expression
- update window_name [as stream_name]
- set property_name = expression [, property_name = expression [,...]] [where criteria_expression]
- // delete
- delete from window_name [as stream_name] [where criteria_expression]
- package example;
- import com.espertech.esper.client.EPAdministrator;
- import com.espertech.esper.client.EPOnDemandQueryResult;
- import com.espertech.esper.client.EPRuntime;
- import com.espertech.esper.client.EPServiceProvider;
- import com.espertech.esper.client.EPServiceProviderManager;
- import com.espertech.esper.client.EventBean;
- import java.io.Serializable;
- /**
- * Created by Luonanqin on 4/9/14.
- */
- class SelectEvent implements Serializable {
- private String name;
- private int size;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getSize() {
- return size;
- }
- public void setSize(int size) {
- this.size = size;
- }
- public String toString() {
- return "name=" + name + ", size=" + size;
- }
- }
- public class SelectWindowTest {
- public static void main(String[] args) {
- EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider();
- EPAdministrator admin = epService.getEPAdministrator();
- EPRuntime runtime = epService.getEPRuntime();
- String selectEvent = SelectEvent.class.getName();
- String epl1 = "create window SelectWindow.win:keepall() as select * from " + selectEvent;
- String epl2 = "insert into SelectWindow select * from " + selectEvent;
- admin.createEPL(epl1);
- admin.createEPL(epl2);
- SelectEvent se1 = new SelectEvent();
- se1.setName("se1");
- se1.setSize(1);
- runtime.sendEvent(se1);
- System.out.println("Send SelectEvent 1: " + se1);
- SelectEvent se2 = new SelectEvent();
- se2.setName("se2");
- se2.setSize(2);
- runtime.sendEvent(se2);
- System.out.println("Send SelectEvent 2: " + se2);
- String select = "select * from SelectWindow";
- String update = "update SelectWindow set name='update1' where size = 2";
- String delete = "delete from SelectWindow where size < 2";
- System.out.println("\nSelect SelectWindow!");
- EPOnDemandQueryResult selectResult = epService.getEPRuntime().executeQuery(select);
- EventBean[] events = selectResult.getArray();
- for (int i = 0; i < events.length; i++) {
- System.out.println(events[i].getUnderlying());
- }
- // 更新size=2的事件,将name改为'update1'
- System.out.println("\nUpdate SelectEvent(size = 2) in SelectWindow!");
- EPOnDemandQueryResult updateResult = epService.getEPRuntime().executeQuery(update);
- events = updateResult.getArray();
- for (int i = 0; i < events.length; i++) {
- System.out.println(events[i].getUnderlying());
- }
- System.out.println("\nSelect SelectWindow!");
- selectResult = epService.getEPRuntime().executeQuery(select);
- events = selectResult.getArray();
- for (int i = 0; i < events.length; i++) {
- System.out.println(events[i].getUnderlying());
- }
- // 删除size<2的事件
- System.out.println("\nDelete SelectEvent(size < 2) in SelectWindow!");
- EPOnDemandQueryResult deleteResult = epService.getEPRuntime().executeQuery(delete);
- events = deleteResult.getArray();
- for (int i = 0; i < events.length; i++) {
- System.out.println(events[i].getUnderlying());
- }
- System.out.println("\nSelect SelectWindow!");
- selectResult = epService.getEPRuntime().executeQuery(select);
- events = selectResult.getArray();
- for (int i = 0; i < events.length; i++) {
- System.out.println(events[i].getUnderlying());
- }
- }
- }
执行结果:
- Send SelectEvent 1: name=se1, size=1
- Send SelectEvent 2: name=se2, size=2
- Select SelectWindow!
- name=se1, size=1
- name=se2, size=2
- Update SelectEvent(size = 2) in SelectWindow!
- name=update1, size=2
- Select SelectWindow!
- name=se1, size=1
- name=update1, size=2
- Delete SelectEvent(size < 2) in SelectWindow!
- name=se1, size=1
- Select SelectWindow!
- name=update1, size=2
10.Explicitly Indexing Named Windows
因为named window中可以存放事件,所以对存有大量的事件的window进行操作时,效率肯定是一个很大的问题。因此Esper支持对named window建立索引,具体来说是对named window中存放的事件的属性建立索引。我没有实际测试过加过索引之后操作时间有没有缩短,所以如果有人测试过并的确有好效果,希望能在本篇评论里向我反馈下,谢谢。
语法如下:
- create [unique] index index_name on named_window_name (property [hash| btree] [, property] [hash|btree] [,...] )
unique代表建立唯一索引,如果插入了重复的行,则会抛出异常并阻止重复行插入。如果不使用此关键字,则表示可以插入重复行。index_name为索引的名称,named_window_name是要建立索引的named window。
后面的括号中包含named window中的属性以及索引类型。索引类型分两种,hash索引不会排序,如果有=操作,建议使用此类型索引。btree索引基于排序二叉树,适合<, >, >=, <=, between, in等操作。如果不显式声明hash或者btree,则默认为hash索引。举例如下:
- // create a unique index on user id(hash) and profile id(hash)
- create unique index UserProfileIndex on UserProfileWindow(userId, profileId)
- // create a non-unique index on symbol(hash) and buyPrice(btree)
- create index idx1 on TickEventWindow(symbol hash, buyPrice btree)
11.Dropping or Removing Named Windows
注销named window的方式是直接调用EPStatement对象的destroy方法。虽然注销,但是named window的名字仍然被占用着,所以你只能重新建立和之前的named window一样结构的window,否则会抛出异常。例如:
- // Create DropWindow
- create window DropWindow.win:keepall() as select * from DropEvent
- // Destroy DropWindow
- EPStatement state = admin.createEPL("create window DropWindow.win:keepall() as select * from DropEvent");
- state.destroy();
- // Create DropEvent again(different with prior epl)
- create window DropWindow.win:keepall() as select name from DropEvent
- // throw Exception