天天看点

程序员的量化交易之路(4)--Esper之事件(3)

这一节中我们继续学习esper的事件部分内容。

对应官方的文档为2.4-2.5

有些情况,一个事件的某个属性本身又是一个事件。esper对这种称作为fragment(碎片)和碎片类型。一个示例就是,两个或者更多的事件可以组成和一个新的事件作为输出,而这个输出事件在将来可能又作为其他事件的一个碎片属性。

碎片及类型属性使得你可以组合事件,而无需使用java 反射api,这减少了事件底层操作处理。相关api见15.6,“event and event type”

pojo是指类对象通过像javabean风格的方法提供getter方法向外界开放内部属性。这种事件类,也不是完全需要严格遵循javabean的约定,但一定要提供getter方法,或者是通过某种配置达到目的。

esper支持javabean风格的事件类,它可以是某个基类的扩展,或者是一个或者多个接口的实现。esper的时间模式和epl语句也支持指向java接口类和抽象类。

代表事件的类应该是不可变的。因为事件代表的是过去发生的动作或者状态的改变,所以应该是不能改变的。但这也不是严格要求,esper引擎也接受可变的事件。

事件类的hashcode和equals方法无需实现。其实现也不会影响esper引擎的工作表现。

前面我们提到,我们支持遵循标准javabean约定的属性类型,斌企鹅有一些是esper特定支持的:

1)  simple 简单属性仅仅包含一个单一的可检索的值。属性的底层实现可能是java语言的内置类型(例如int,简单对象java.lang.string)或更为复杂的对象,它可能是由java语言定义的、或者是应用定义的,或是第三方库定义的。

2)  indexed 索引属性存储的是同一类型的有序对象容器,容器内的对象可以通过索引单独访问。

3)  mapped javabean api的扩展,esper考虑任何由以string类型作为key的映射属性。

4)  nested 嵌套属性是指该属性所在的对象是一个事件的一个属性。即它是事件属性的属性。

假如这里有个newemployeeevent事件类。这里的索引和映射属性返回的是java对象,但也可以返回java的内置类型(例如int和string)。address对象和employee对象都可以嵌套它们自己的属性,例如address里面可以有街道名称,employee中可以有雇员姓名。

public classnewemployeeevent {

public stringgetfirstname();

public addressgetaddress(string type);

public employeegetsubordinate(int index);

public employee[]getallsubordinates();

}

简单事件属性需要一个getter方法,用于返回属性值。在这个例子中,getfirstname方法返回firstname事件属性,它为string类型。

索引事件属性需要如下的两种getter方法的至少一种。第一种,以整形为参数返回一个属性值,例如getsuborinate方法;另一种方法是返回整个数组对象,例如getallsubordinates方法。在epl或者事件模式语句中,索引属性通过property[index]来访问。

映射事件属性需要一个getter方法,它以string类型的关键字作为参数,返回属性值,例如getaddress方法。在epl或者事件模式语句中,映射属性通过property(‘key’)来访问。

嵌套事件属性需要一个getter方法用于返回嵌套对象。getaddress和getsubordinate是映射和索引属性,它们返回的是一个嵌套对象。在epl和事件模式语句中,嵌套属性通过property.nestedproperty来访问。

上述的这些属性可以任意的进行复合。例如下面就是这些属性的一些复合示例:

everynewemployeeevent(firstname='myname')

everynewemployeeevent(address('home').streetname='park avenue')

everynewemployeeevent(subordinate[0].name='anothername')

everynewemployeeevent(allsubordinates[1].name='thatname')

everynewemployeeevent(subordinate[0].address('home').streetname='water street')

类似的,这些语法可以应用在epl语句任何事件属性名可以出现的地方,例如select列表,where语句,jion语句等。

select firstname,address('work'), subordinate[0].name, subordinate[1].name

from newemployeeevent

whereaddress('work').streetname = 'park ave'

属性名遵循java标准:java.beans.introspector类和getbeaninfo方法返回属性名。此外,esper还可以通过配置一个标识来关闭大小写敏感,表2.4是属性名和相应getter方法的示例。

方法 属性名 示例

getprice()

price select pricefrom myevent

getname()

name select name frommyevent

getitemdesc()

itemdesc

select itemdesc frommyevent

getq() q select qfrom myevent

getqn() qn select qnfrom myevent

gets() s select sfrom myevent

2.5.3 参数化类型

当你的getter方法的到的是一个参数化的类型,例如索引属性,iterable<myeventdata>,映射属性map<string,myeventdata>,那么这个参数化类型就是指向属性的属性表达式,它可以获得属性值。

  public stringgetname();

  public iterable<educationhistory>geteducation();

  publicmap<string, address> getaddresses();

一个获得属性的表达式如下:

select name,education, education[0].date, addresses('home').street

epl语句可以更新事件的索引和映射属性,提供了设置属性的setter方法。

索引属性的setter方法必须形如setpropertyname,并且有两个参数,整形的索引参数和object类型的属性新值。

映射属性的setter方法,必须是形如setpropertyname,并且接受两个参数,string类型的关键字和object类型的属性值。

下面就是设置事件索引和映射属性的一个示例:

public class myevent{

  private mapprops = new hashmap();

  privateobject[] array = new object[10];

  public voidsetprops(string name, object value) {

   props.put(name, value);

  }

  public voidsetarray(int index, object value) {

   array[index] = value;

  // ... alsoprovide regular javabean getters and setters for all properties

下面语句是设置索引和映射属性:

update istreammyeventstream set props('key') = 'abc', array[2] = 100

esper是获得事件属性的字节码,当字节码获取失败时,这时候引擎会记录一个警告并使用java反射机制去获得属性值。

一个已知的局限性是,当想获得一个属性值,但真实获得的却是属性值子类的对象,引擎就会告警。