关于EPL,已经写了三篇了,预估计了一下,除了今天这篇,后面还有5篇左右。你们可别嫌多,官方的文档对EPL的讲解有将近140页,我已经尽可能将废话都干掉了,再配合我附上的例子,看个人10篇文章比那140页英文文档确定舒服多了吧。也请各位原谅我一周一篇的速度,毕竟我还要学习,生活,工做,一个都不能少。java
今天讲解的内容包括三块:Order by,Limit,Insert into。你们会SQL的应该很熟悉这三个东西,前两个比较简单,Insert into会有一些差异,篇幅也相对多些。express
1.Order by数组
EPL的Order by和SQL的几乎如出一辙,做用都是对输出结果进行排序,可是也有一些须要注意的地方。语法以下:app
expreession表示要排序的字段,asc表示升序排列(从小到大),desc表示降序排列(从大到小)。举个例子:ide
使用方法很简单,除了和SQL类似的特色外,还有他本身须要注意的几点:函数
a. 若是不特别说明是升序仍是降序,默认状况下按照升序排列。学习
b. 若是order by的子句中出现了聚合函数,那么该聚合函数必须出如今select的子句中。this
c. 出如今select中的expression或者在select中定义的expression,在order by中也有效。spa
d. 若是order by所在的句子没有join或者没有group by,则排序结果幂等,不然为非幂等。.net
2. Limit
Limit在EPL中和在SQL中也基本同样,不过SQL中是用具体的数字来表示限制范围,而EPL能够是常量或者变量来表示限制范围。语法以下:
row_count表示输出多少行,能够是一个整型常量,也能够是一个整型变量,以方便运行时修改。
offset_count表示在当前结果集中跳过n行而后再输出,一样也能够是一个整型变量。若是不使用此参数,则表示跳过0行,即从第一行输出。举例以下:
除了以上的语法,limit还有一种简化的写法,其实是参照SQL的标准。
两个参数的含义和上面的同样,而且咱们将上面的例子改写一下:
若是这个两个参数是负数会怎么样呢?
row_count为负数,则无限制输出,若为0,则不输出。当row_count是变量表示而且变量为null,则无限制输出。
offset _count是不容许负数的,若是是变量表示,而且变量值为null或者负数,则EPL会把他假设为0。
3. Insert into
3.1 简单用法
EPL的Insert into和SQL的有比较大的区别。SQL是往一张表里插入数据,而EPL是把一个事件流的计算结果放入另外一个事件流,而后能够对这个事件流进行别的计算。因此Insert into的一个好处就是能够将是事件流的计算结果不断级联,对于那种须要将上一个业务的结果数据放到下一个业务处理的场景再适合不过了。除此以外,Insert into还有合并多个计算结果的做用。到这里相信你们已经对他愈来愈好奇了,不急,我们先来看看语法:
event_stream_name定义了事件流的名称,在执行完insert的定义以后,咱们可使用select对这个事件流进行别的计算。
istream | irstream | rstream表示该事件流容许另外一个事件的输入/输入和输出/输出数据可以进入(解释好像很绕。。一下子看例子就能明白了)
property_name表示该事件流里包含的属性名称,多个属性名之间用逗号分割,而且用小括号括起来。
上面的说明可能不是很好理解,我们先看个例子:
从例子中能够看到,insert into须要配合select进行使用,以代表前一个事件流有哪些计算结果将进入insert into定义的事件流。而且在select中的字段要和insert里的事件流的属性要对应(这里指的对应是数据类型对应,并且属性数量也必须同样)。若是说insert定义的事件流名称在以前已经定义过(insert into中定义的除外),重名是不容许的。
我我的推荐第二种写法,经过as设置的别名即为insert定义的事件流的属性,这样能够避免属性的个数不一致的错误。
刚才说了istream | irstream | rstream的用法,可能有点表述不清楚,这里看一个完整的例子。
执行结果:
这个例子中,insertEPL表示当Asus事件从length为1的view中移除时,把移除的事件放入Computer。insertSelectEPL是对Computer的事件流进行计算,这里只是在每进入两个事件时才输出这两个事件的cid。而rstream在这里的表现,从执行结果中能够看到,在进入id为1 2 3的事件后,insertSelectEPL的监听器被触发,由于id为1和2的事件是在发送了Asus的id为2和3的事件以后被移除了,以后就进入了Computer,并知足了length=2,所以在监听器里看到有id为1和2的事件进入了Computer。
若是不显示指定rstream,则insert into只容许istream的事件流进入Computer。若是指定为irstream,那么进入的和移除的Asus都会进入到Computer。
上面的例子都是指定了insert into里事件流会有什么属性,若是不指定会是什么结果呢?请看例句:
很容易想到,这里其实是把进入引擎的Asus事件都传递到Computer定义的事件流中,而且属性什么的彻底和Asus同样,能够说是Asus的一个复制版本,只是名字不同。也许有人以为这么作没什么意思,直接计算Asus事件流不就能够了么,实际上在业务处理数据时,这种作法就能够屏蔽掉外部的数据来源,作到业务层上的隔离。
假设Asus中还包含其余的JavaBean,一样也能够将这个Bean的数据传递到另外一个事件流中。例句以下:
3.2 Merge Event Stream
insert into除了接收一个流的事件,同时也支持多个流的合并。通俗一点来讲,合并的流数据要一致才能够合并。并且在第一次定义insert的事件流之后,别的事件流想要被合并就必须和以前定义的属性数量和数据类型对应。举例以下:
若是说select了多个事件流,可是你只想输入其中一个,应该像下面这样写:
除此以外,EPL还支持调用函数转换事件后再输入insert into:
注意,使用自定义函数必定要返回javabean,map,或者Object数组,且不能用as来为转换后的结果设置别名。
3.3 Decorated Events
以前所见到的不是将事件流总体输入insert,就是将事件流的部分属性输入insert。实际上能够将事件流总体和事件流属性组成的复杂表达式一块儿放入insert。示例以下:
若是说别的事件流想进入此insert,那么事件流属性必定要和第一个*表示的全部属性相同。
3.4 Event Objects Instantiated by insert into
前面的全部例子中,对于insert into的事件结构都是在insert子句中配合select子句进行定义的。若是咱们想用已经定义好的事件结构是否能够呢?答案是确定的。可是若是事件是javabean,而且事先没有注册到引擎,则须要insert子句中写上类的全名。例如:
固然,若是在使用以前有注册过,那么使用注册时的名称也是能够的。
由于事件结构是早就定义好的,因此在写select的时候就必须符合insert事件中的属性了,若是属性名称不同须要使用as加上别名,同样的能够不用设置别名,且数据类型也要一一对应。例如:
可是这种用法在Computer存在包含了参数的构造方法时就显得没那么必须了。先看一个完整例子,你也许就会明白了。
执行结果:
这里的执行结果很容易理解,关键是carToAutoEpl和carToBenzEpl两个句子。
对于Auto的JavaBean,咱们能够发现它包含一个有参数的构造函数且没有属性对应的set方法,在carToAutoEpl中,select的内容并无和属性名称对应起来。这种写法确实是正确的,正由于Auto中定了含参的构造函数,才使得select能够写的更随意。可是必定要记住,构造函数里的参数顺序必定要和select中的属性的数据类型对应起来,若是这里把name和size互换位置,一定报错!
对于Benz的JavaBean,能够看到每一个属性都有对应的set方法,而没有含参的构造函数,因此select中属性的名称须要as来设置别名。固然,像benzEpl2那种写法,一样能够避免select中设置别名。
一句话总结,若是JavaBean中有含参的构造函数,EPL中不须要显示写出属性名称。若是没有构造函数,那么必须包含set方法,且select中要写出具体的属性。这几种写法各有各的好处,你们使用时可针对具体的状况选择性使用。