Esper学习之十一:EPL语法(七)

上一篇说到了EPL如何访问关系型数据库这种数据源,实际上别的数据源,比如:webservice、分布式缓存、非关系型数据库等等,Esper提供了统一的数据访问接口。然后今天会讲解如何创建另外一种事件类型——Schema

1.Joining Method Invocation Results
和执行sql的语法类似,调用方法的一种触发方式也是通过join别的事件的属性来达到效果,且调用方法的句子为from子句。语法如下:

[plain] view plaincopy

  1. method:class_name.method_name(parameter_expressions)

method是固定关键字,class_name为类全名,方法名为返回外部数据的方法名,parameter_expressions为方法的参数列表,对应join的事件属性,多个属性之间用逗号分隔,参数整体用圆括号括起来。例如:

[plain] view plaincopy

  1. select * from AssetMoveEvent, method:MyLookupLib.lookupAsset(assetId) // assetId为AssetMoveEvent的属性之一

除了简单join,还可以为join加上where条件过滤一些返回结果。例如:

[plain] view plaincopy

  1. select assetId, assetDesc from AssetMoveEvent as asset,
  2. method:MyLookupLib.getAssetDescriptions() as desc    //调用的方法无参
  3. where asset.assetid = desc.assetid

Esper不仅能缓存执行sql的查询结果,也能缓存执行方法的查询结果,并且缓存策略也是两种:LRU和Expire Time。具体可以参考上一篇缓存配置章节。若存在返回结果,且缓存生效后,Esper会自动为返回结果简历索引,加快查询速度。配置范例如下:

[html] view plaincopy

  1. // LRU Cache
  2. <method-reference class-name="MyFromClauseWebServiceLib">
  3. <lru-cache size="1000"/>
  4. </method-reference>
  5. // Expire Time Cache
  6. <method-reference class-name="com.mycompany.MyFromClauseLookupLib">
  7. <expiry-time-cache max-age-seconds="10" purge-interval-seconds="10" ref-type="weak"/>
  8. </method-reference>

class-name表示方法所在的类,可以是类全名,可以只有类名,前提是包已经import。其他参数的解释请参见上一篇缓存配置章节

2.Polling Method Invocation Results via Iterator
除了Join别的事件来触发查询方法,进而触发Listener,Esper还支持通过API直接执行方法。例如:

[plain] view plaincopy

  1. select * from method:MyLookupLib.getAssetDescriptions(category_var)   // category_var为注册到引擎的变量。

3.Method Definition
为了能够以一种统一的结构访问外部数据(RDBMS除外),Esper提供了调用静态方法的形式访问外部数据。具体解释如下:
a.返回数据的方法必须是公共静态方法。方法参数可以有多个也可以没有。
b.如果返回一条数据或无返回数据,则方法的返回类型可以是Java类或者Map类型数据。如果返回多条数据(包括一条),则方法返回类型必须是Java类的数组或者Map数组。
c.如果方法的返回类型是Java类或者Java类数组,则Java的类定义必须包含针对属性的get方法。
d.如果方法的返回类型是Map或者Map数组,则Map的key-value定义固定为<String, Object>。
e.如果返回的数据是Map或者Map数组,除了定义返回数据的方法外,还要定义返回元数据的方法(这个元数据针对返回的数据)。方法是公共静态方法,且必须是无参数方法。方法返回类型为Map<String, Class>,String表示返回的数据的名称,Class表示返回的数据的类型。返回元数据的方法名称=返回数据的方法名称+Metadata。

下面举一个完整的例子总结前面说的三点:

[java] view plaincopy

  1. package example;
  2. /**
  3. * 返回Java类型的外部数据
  4. *
  5. * Created by Luonanqin on 2/16/14.
  6. */
  7. class JavaObject {
  8. private String name;
  9. private int size;
  10. public String getName() {
  11. return name;
  12. }
  13. public void setName(String name) {
  14. this.name = name;
  15. }
  16. public int getSize() {
  17. return size;
  18. }
  19. public void setSize(int size) {
  20. this.size = size;
  21. }
  22. public String toString() {
  23. return "JavaObject{" + "name=‘" + name + ‘\‘‘ + ", size=" + size + ‘}‘;
  24. }
  25. }
  26. public class InvocationMethodJava {
  27. public static JavaObject[] getJavaObject(int times) {
  28. JavaObject[] javaObjects = new JavaObject[2];
  29. JavaObject javaObject1 = new JavaObject();
  30. javaObject1.setName("javaObject1");
  31. javaObject1.setSize(1 * times);
  32. JavaObject javaObject2 = new JavaObject();
  33. javaObject2.setName("javaObject2");
  34. javaObject2.setSize(2 * times);
  35. javaObjects[0] = javaObject1;
  36. javaObjects[1] = javaObject2;
  37. return javaObjects;
  38. }
  39. }
  40. package example;
  41. import java.util.HashMap;
  42. import java.util.Map;
  43. /**
  44. * 返回Map类型的外部数据
  45. *
  46. * Created by Luonanqin on 2/16/14.
  47. */
  48. public class InvocationMethodMap {
  49. public static Map<String, Object> getMapObject() {
  50. Map<String, Object> map = new HashMap<String, Object>();
  51. map.put("name", "mapObject1");
  52. map.put("size", 1);
  53. return map;
  54. }
  55. public static Map<String, Class> getMapObjectMetadata() {
  56. Map<String, Class> map = new HashMap<String, Class>();
  57. map.put("name", String.class);
  58. map.put("size", int.class);
  59. return map;
  60. }
  61. }
  62. package example;
  63. import java.util.Iterator;
  64. import com.espertech.esper.client.EPAdministrator;
  65. import com.espertech.esper.client.EPRuntime;
  66. import com.espertech.esper.client.EPServiceProvider;
  67. import com.espertech.esper.client.EPServiceProviderManager;
  68. import com.espertech.esper.client.EPStatement;
  69. import com.espertech.esper.client.EventBean;
  70. import com.espertech.esper.client.UpdateListener;
  71. /**
  72. * Created by Luonanqin on 2/16/14.
  73. */
  74. class Times {
  75. private int times;
  76. public int getTimes() {
  77. return times;
  78. }
  79. public void setTimes(int times) {
  80. this.times = times;
  81. }
  82. }
  83. class InvocationMethodListener implements UpdateListener {
  84. public void update(EventBean[] newEvents, EventBean[] oldEvents) {
  85. if (newEvents != null) {
  86. System.out.println(newEvents[0].getUnderlying());
  87. System.out.println(newEvents[1].getUnderlying());
  88. }
  89. }
  90. }
  91. public class InvocationMethodTest {
  92. public static void main(String arg[]) {
  93. EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider();
  94. EPRuntime runtime = epService.getEPRuntime();
  95. EPAdministrator admin = epService.getEPAdministrator();
  96. /**
  97. * 调用外部方法返回Java类型数据
  98. */
  99. String timesName = Times.class.getName();
  100. String ijName = InvocationMethodJava.class.getName();
  101. String epl1 = "select ij.* from " + timesName + " as t, method:" + ijName + ".getJavaObject(times) as ij";
  102. System.out.println(epl1+"\n");
  103. EPStatement state1 = admin.createEPL(epl1);
  104. state1.addListener(new InvocationMethodListener());
  105. Times times = new Times();
  106. times.setTimes(2);
  107. runtime.sendEvent(times);
  108. System.out.println("");
  109. /**
  110. * 调用外部方法返回Map类型数据
  111. */
  112. String imName = InvocationMethodMap.class.getName();
  113. String epl2 = "select * from method:" + imName + ".getMapObject()";
  114. System.out.println(epl2+"\n");
  115. EPStatement state2 = admin.createEPL(epl2);
  116. Iterator<EventBean> iter = state2.iterator();
  117. while (iter.hasNext()) {
  118. EventBean event = iter.next();
  119. System.out.println(event.getUnderlying());
  120. }
  121. }
  122. }

4.Declare an Event Type by Providing Names and Types
       我曾经在《Esper学习之二:事件类型》里说过,事件类型的定义可以是POJO,数组,Map,或者XML。实际上还有另一种定义事件类型的方法,那就是schema。这个schema可不是数据库中的schema,而是用EPL定义的事件类型,所以说此类事件类型是针对Esper设计的,并不能拿出来通用。

我们先从语法开始说起。

[plain] view plaincopy

  1. create [map | objectarray] schema schema_name [as]
  2. (property_name property_type [,property_name property_type [,...])
  3. [inherits inherited_event_type[, inherited_event_type] [,...]] [starttimestamp timestamp_property_name]
  4. [endtimestamp timestamp_property_name]
  5. [copyfrom copy_type_name [, copy_type_name] [,...]]

解释如下:

a.map objectarray分别表示当前定义的schema是map结构还是数组结构。
b.schema_name表示schema的名字,全局唯一。as为可选内容。
c.property_name表示schema所包含的属性名称,property_type为属性的类型,多个属性用逗号分隔,所有属性用圆括号括起来可以使用的类型有:int、String等已经内置的Java类型;已经通过Configuration接口注册的事件类型,比如Map,数组,schema等;可以使用POJO类,如果没有import就要写全名,否则写类名即可。
d.inherits表示继承别的事件类型,后面跟着的是要继承的事件类型。如果使用了继承,则当前定义的schema包含了继承的事件类型的所有属性。并且可以继承多个,用逗号分隔。
e.starttimestamp和endtimestamp是两个特殊的关键字。单独使用starttimestamp时,表示为schema记一个时间戳。后面跟着已经声明的属性并且能够返回一个data-time值。如果联合endtimestamp使用,则表示这个schema只能在某段事件内使用。后面跟着的同样也是已经声明的属性并且能够返回一个data-time值。注意endtimestamp不能单独使用。
f.copyfrom表示复制别的事件的所有属性到当前定义的schema中,并且可以copy多个事件,用逗号分隔。

下面用几个例子来一一展示如何使用上面的语法:

[plain] view plaincopy

  1. // 声明SecurityEvent
  2. create schema SecurityEvent as (ipAddress string, userId String, numAttempts int)
  3. // 声明AuthorizationEvent,并且包含com.mycompany.HostNameInfo类型的hostinfo属性
  4. create schema AuthorizationEvent(group String, roles String[], hostinfo com.mycompany.HostNameInfo)
  5. // 声明CompositeEvent,并且包含了SecurityEvent数组作为innerEvents属性的类型
  6. create schema CompositeEvent(group String, innerEvents SecurityEvent[])
  7. // 声明WebPageVisitEvent,自己定义了userId属性,并且继承了PageHitEvent的所有属性
  8. create schema WebPageVisitEvent(userId String) inherits PageHitEvent
  9. // 声明RoboticArmMovement,并且开始于startts,结束于endts
  10. create schema RoboticArmMovement (robotId string, startts long, endts long) starttimestamp startts endtimestamp endts
  11. // 声明ExtendedSecurityEvent,并且复制SecurityEvent事件的所有属性到ExtendedSecurityEvent
  12. create schema ExtendedSecurityEvent (userName string) copyfrom SecurityEvent
  13. // 声明WebSecurityEvent,并且复制SecurityEvent和WebPageVisitEvent事件的所有属性到WebSecurityEvent
  14. create schema WebSecurityEvent (userName string) copyfrom SecurityEvent, WebPageVisitEvent

这里要额外说一下,继承不仅仅继承了事件的属性,如果被继承的事件定义了starttimestamp或者endtimestamp,同样也会被继承下来。但是copyfrom是不会吧starttimestamp和endtimestamp复制的。这点一定要注意。

对于map和objectarray这两个关键字,可以用注解达到同样的效果。例如:

[plain] view plaincopy

  1. // 声明数组类型的schema
  2. create objectarray schema SchemaTest1 as (prop1 string);
  3. ... equals ...
  4. @EventRepresentation(array=true)create schema SchemaTest1 as (prop1 string);
  5. // 声明Map类型的schema
  6. create map schema SchemaTest2 as (prop1 string);
  7. ... equals ...
  8. @EventRepresentation(array=false)create schema SchemaTest2 as (prop1 string);

5.Declare Variant Stream
Variant Stream简单来说就是包含了各种不同的事件类型的事件类型。所以语法也很明了:

[plain] view plaincopy

  1. create variant schema schema_name [as] eventtype_name|* [, eventtype_name|*] [,...]

variant为关键字,表明这是Variant Stream,eventtype_name为事件的定义名,多个事件定义用逗号分隔开。*表示接收任何的事件类型,不过一般来说没有需求会到这种程度。举例如下:

[plain] view plaincopy

  1. // 声明SecurityVariant,包含了LoginEvent和LogoutEvent
  2. create variant schema SecurityVariant as LoginEvent, LogoutEvent
  3. // 声明AnyEvent,包含任何类型的事件
  4. create variant schema AnyEvent as *

以上就是调用外部方法以及schema的创建讲解,尤其是schema的创建,可能大家会用的更多一些,最好能记住。

时间: 2024-10-12 16:17:50

Esper学习之十一:EPL语法(七)的相关文章

Esper学习之七:EPL语法(三)

1.Aggregation 和SQL一样,EPL也有Aggregation,即聚合函数.语法如下: [plain] view plaincopy aggregate_function([all|distinct] expression) aggregate_function就是聚合函数的名字,比如avg,sum等.expression通常是事件流的某个属性,也可以是不同事件流的多个属性,或者是属性和常量.函数之间的运算.举例如下. [plain] view plaincopy // 查询最新5秒

Esper学习之五:EPL语法(一)

上篇说到了Esper的Context,要是不了解的同学请参看<Esper学习之四:Context>,看过的同学如果还是不理解的话可以给我评论,我将会尽可能的解答.之前有些同学问我Context和Group by有什么区别,其实如果只是很简单的用Context,那么确实没太大区别,无非是在Context下select可以不包含group by修饰的属性.但是Group by明显没有Context强大,很多复杂的分组Group by是没法做到的.不过在能达到同样效果的情况下,我还是建议使用Grou

Esper学习之十二:EPL语法(八)

今天的内容十分重要,在Esper的应用中是十分常用的功能之一.它是一种事件集合,我们可以对这个集合进行增删查改,所以在复杂的业务场景中我们肯定不会缺少它.它就是Named Window. 由于本篇篇幅较长,希望各位童鞋慢慢阅读,并仔细研究文档中或者我给出的例子. 1.Create Named Window 本篇的开头有说过named window是一种事件集合,它可以存储一种类型或多种类型的事件.如果我们不移除named window中的事件,那么事件应该存在生命周期,否则事件过多会有内存溢出的

Esper学习之三:进程模型

之前对Esper所能处理的事件结构进行了概述,并结合了例子进行讲解,不清楚的同学请看Esper学习之二:事件类型.今天主要为大家解释一下Esper是怎么处理事件的,即Esper的进程模型. 1.UpdateListener UpdaterListener是Esper提供的一个接口,用于监听某个EPL在引擎中的运行情况,即事件进入并产生结果后会通知UpdateListener.接口如下 [java] view plaincopy package com.espertech.esper.client

#HTTP协议学习# (十一)理解HTTP幂等性

在httpcomponent 文档中看到如下段落: 1.4.1. HTTP transport safety It is important to understand that the HTTP protocol is not well suited to all types of applications. HTTP is a simple request/response oriented protocol which was initially designed to support s

【转】MYSQL入门学习之十一:触发器的基本操作

转载地址:http://www.2cto.com/database/201212/176781.html 触发器是MySQL响应以下任意语句而自动执行的一条MySQL语句(或位于BEGIN和END语句之间的一组语句):  www.2cto.com DELETE: INSERT: UPDATE: 使用触发器,需要MySQL5或之后的版本支持. 一.触发器基本操作 1.创建触发器 创建触发器时,需要给出4条信息: 唯一的触发器名:(虽然MySQL5允许不同的表上的触发器名称相同,但一般最好不要这么做

从零开始学习jQuery (十一) 实战表单验证与自动完成提示插件

原文:从零开始学习jQuery (十一) 实战表单验证与自动完成提示插件 本系列文章导航 从零开始学习jQuery (一) 开天辟地入门篇 从零开始学习jQuery (二) 万能的选择器 从零开始学习jQuery (三) 管理jQuery包装集 从零开始学习jQuery (四) 使用jQuery操作元素的属性与样式 从零开始学习jQuery (五) 事件与事件对象 从零开始学习jQuery (六) jQuery中的Ajax 从零开始学习jQuery (七) jQuery动画-让页面动起来! 从零

C++语言学习(十一)——多态

C++语言学习(十一)--多态 一.多态简介 C++中的多态(polymorphism)是指由继承而产生的相关的不同的类,其对象对同一消息会作出不同的响应.多态性是面向对象程序设计的一个重要特征,能增加程序的灵活性.可以减轻系统升级,维护,调试的工作量和复杂度.多态是一种不同层次分类下的重要联系,是一种跨层操作. 二.多态实现的前提 赋值兼容规则是指在需要基类对象的任何地方都可以使用公有派生类的对象来替代.赋值兼容是一种默认行为,不需要任何的显式的转化步骤,只能发生在public继承方式中,是多

《Hibernate学习笔记十一》:树状结构设计

<Hibernate学习笔记十一>:树状结构设计 这是马士兵老师讲解Hibernate的一个作业题,树状结构设计,这是一个比较典型的例子,因此有必要写篇博文记录下. 树状结构的设计,它是在同一个类中使用了多对一(ManyToOne)和一对多(OneToMany). 在完成这个题目我们应该按照如下的步骤进行: 1.先思考数据库的模型应该是什么样的?? 数据库中的模型应该如下:即存在id p_id 2.思考面向对象的模型,及如何来进行映射??? 根据数据库中表的特点,对象应该有id name;由于