天天看點

程式員的量化交易之路(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反射機制去獲得屬性值。

一個已知的局限性是,當想獲得一個屬性值,但真實獲得的卻是屬性值子類的對象,引擎就會告警。