Fork me on GitHub

深入浅出事件流处理NEsper(二)

NEsper使用的事件类型来描述事件的类型信息。你的应用在启动时可能预先配置定义事件类型,或者在运行时通过API或EPL语法动态的增加事件类型。

EPL中的create schema 的语法允许在运行时用EPL申明一个事件类型。

2.1事件对象

事件是过去发生的动作或状态变化的一个不可改变的记录。事件属性捕捉事件的状态信息。

在ESPER中,事件是可以被描述成以下任何一种CLR对象:

image

NEsper为声明一个事件提供了多种的选择,没有绝对的需要用户去创建一个CLR对象来代表一个事件。事件表达有以下共性:

• 所有的事件表示支持嵌套,索引和映射属性(亦称属性表达),在下面详细解释前。嵌套级别没有限制。

• 所有的事件表示提供事件类型元数据。这包括嵌套属性的类型元数据。

• 所有事件表示允许调换事件本身和部分属性图到新的事件。条件调换是指选择那些本身是嵌套的属性图的事件本身或事件属性,然后查询事件的性质或嵌套属性图。Apache的Axiom事件表示是一个例外,目前不允许调换的事件属性,但允许调换的事件本身。

• CLR对象和Map描述允许超类型。

所有事件表示的API的行为是相同的,在这一章中指出的少数例外。多个事件陈述的好处有:

• 对于已经支持的陈述事件的应用程序,没有必要作事件到CLR对象的转换处理。

• 事件陈述是交互的,当事件陈述发生改变时,需要减少或消除变更声明。

• 事件陈述是可共同使用的,允许所有的事件表示在相同或不同报表中的共同使用。

• 选择使得其可能自觉地权衡性能,易于使用。

2.2事件属性

事件属性捕捉事件的状态信息。事件属性的简单的索引,映射和嵌套的事件属性。下表列出了不同类型的属性和它们的语法在事件表达中。该语法允许语句来查询深CLR 对象图,XML结构和MAP事件。 如下图:

image

合并也有可能。例如,一个有效的组合,可以的Person.Address("home”).street[0]。

2.2.1转义字符

如果你的应用程序使用System.Collection.Generic.IDictionary或者XML描述事件,事件属性名称会包括一个点号(“.”)字符。反斜杠(“\”)可以用来转换点号,允许事件名称中包括点号。

select part1\.part2 from MyEvent

有时,你的事件属性可能会重叠EPL语言关键字。在这种情况下,你可以使用向后撇号'字符转义属性的名称。

下例假定一个Quote事件,有一个order的属性,而order也是一个保留关键字:

select `order` from Quote

2.3动态属性

动态(未选中)属性是不需要在语句的编译时知道的事件属性。这些属性是在运行过程中解析。

动态属性背后的想法是,对于一个给定的潜在事件,我们并不总是事先知道的所有属性。一个潜在的事件可能在语句的编译时不附加属性,而我们要查询。尤其是丰富的,面向对象的域模型的事件表示非常有用的概念。

动态属性的语法包含属性的名称和一个问号。索引,映射和嵌套的属性也可以动态特性。

动态属性总是返回System.Object的类型。此外,如果在运行时动态属性不存在,动态属性返回一个空值。

例如,考虑一个OrderEvent事件提供了一个“item”属性。 “item”属性是类型对象且持有服务或产品的一个实例的引用。

假设服务和产品类提供了一个名为“price”的属性。通过一个动态的属性,我们可以指定一个查询,以获得从任一对象​​(服务或产品)的price属性:

select item.price? from OrderEvent

另一个例子,假设Server类包含一个serviceName属性,而Product类不拥有,下面的查询返回Server对象的serviceName属性。对于没有serviceName属性的Product对象,将返回一个空值:

select item.serviceName? from OrderEvent

考虑OrderEvent有多个实现类,其中有一些timestamp属性的情况。下一个查询返回的这些实现OrderEvent接口功能的实例的timestamp属性:

select timestamp? from OrderEvent

上面的查询返回类型事件的单个列名timestamp?

当为嵌套的动态属性,动态属性的所有属性也考虑动态特性。在下面的例子中的查询要求direction属性对象返回的detail的动态属性:

select detail?.direction from OrderEvent

上面的EPL等同于如下:

select detail?.direction? from OrderEvent

与动态属性协同提供的有用的函数如下:

• CAST函数动态属性(或表达式的值)转换成给定的类型。

• exists函数检查是否存在一个动态的属性。如果事件有该名称的属性,返回true,否则返回false。

• instanceof函数检查动态属性的值(或表达式的值)是否是任何给定的类型。

• typeof函数返回字符串类型的动态属性名称。

动态事件属性与所有CLR对象,基于Map和XML基于DOM的事件一起工作。

2.4 Fragment and Fragment 类型

有时一个事件的属性能是事件本身。ESPER使用条款碎片和碎片类型来表示这种事件。最好的例子是一个模式相匹配的两个或两个以上的事件且输出事件包含匹配的事件作为片段。换句话说,输出事件由更多的事件,碎片组成的复合事件。

片断具有相同的元数据作为其封装的复合事件。封装的复合事件的元数据包含属性是片段的信息,或有一个属性值能代表片断或者事件本身。

片段和类型的元数据,可以让您的应用程序导航的复合事件,而不需要使用CLR反射API和减少耦合底层的事件表示。

2.5普通的原CLR对象事件

普通的旧式CLR对象的事件是通过CLR 风格的getter方法​​,暴露事件属性的对象实例。事件类或接口不完全符合CLR 规范的;但是Esper引擎来获取事件属性,所需的Get属性,​必须是当前的或一个可以通过配置中定义的访问器方法。

NEsper支持CLR 风格的事件类扩展的超类或实现一个或多个接口。此外,NEsper事件模式和EPL申明可以参考CLR 接口类和抽象类。

代表事件的类应是一成不变的。由于事件是记录状态改变或过去发生的行动,有关事件属性不应该改变的。然而,这是不是一个硬性的要求,NEsper引擎接受事件还是可变的。

没有必要实现GetHashCode和Equals方法。这些方法的实施是CLR事件类,不影响引擎的任何方式的行为。

2.5.1 CLR对象事件

如前所述,不同的属性类型都支持标准的CLR规范,且有些具有NEsper的独特支持:

Simple- 属性可以检索单个值。相关的属性类型可能是原始CLR 语言(如INT,一个简单的对象(如System.String),或更复杂的对象,复杂对象是由CLR语言的应用程序定的,或一个类库包含的应用程序。

Indexed -索引属性存储,可以单独由一个整数值,非负指数(或下标)来访问的对象(同一类型的所有)的有序集合。

Mapped -NEsper接受字符键值对映射属性的任何属性。

Nested -嵌套属性是一个属性所属的CLR对象本身就是另一个事件的属性。

如下图所示,假设有NewEmployeeEvent事件类。在这个例子中返回CLR对象的映射和索引属性,但也可能返回CLR 语言中的原始类型(如int或String)。Address对象和Employee有嵌套属性,如Address对象的街道名称或Employee对象的雇员名称。

public class NewEmployeeEvent {
      public String FirstName { get; }
      public Address GetAddress(String type);
      public Employee GetSubordinate(int index);
      public Employee[] AllSubordinates { get; }
}

Simple事件属性需要返回属性值的getter属性。在这个例子中,FirstName 属性​​返回String型的firstName属性。

Indexed事件属性要求任何一个以下的getter方法。一是采用一个整数类型作key值,并返回该属性的值的方法,如GetSubordinate,或一个返回数组类型,或实现迭代的类的方法。例如getSubordinates 方法,返回一个Employee 数组,但也可能返回一个可迭代的。 EPL或事件模式的语句,索引属性通过[index]语法访问。

Mapped事件属性需要一个getter方法,该方法通过键值对并返回该属性的值,如GetAddress方法。 EPL或事件模式声明,映射属性通过属性(“key”)语法访问。

Nested事件属性需要一个getter方法返回嵌套对象。 GetAddress和 GetSubordinate方法映射和索引返回一个嵌套对象的属性。 EPL或事件模式声明,嵌套的属性是通过property.nestedProperty语法访问。.

所有事件的模式和EPL表达式允许使用索引,映射和嵌套属性(或这些的联合)。下面的例子显示事件模式表达式的过滤器(每行是一个单独的EPL表达式)的索引,映射和嵌套属性的不同组合:

every NewEmployeeEvent(firstName='myName')

every NewEmployeeEvent(address('home').streetName=' Park Avenue')

every NewEmployeeEvent(subordinate[0].name='anotherName')

every NewEmployeeEvent(allSubordinates[1].name='thatName')

every NewEmployeeEvent(subordinate[0].address('home').streetName='Water Street')

同样,语法可用于在EPL表达式在所有可以预测的事件属性名称的情况下,如在select列表,where条件或加入标准。

select firstName, address('work'), subordinate[0].name, subordinate[1].name from NewEmployeeEvent where address('work').streetName = 'Park Ave'

2.5.2属性名称

NEsper配置提供了一个关闭区分大小写的属性名称的标志。下图是getter方法​​和属性名称的示例列表:

image

2.5.3常量和枚举

常量是在CLR 类中用public static const声明的成员,也可参与各种表现形式,如这个例子所示:

select * from MyEvent where property=MyConstantClass.FIELD_VALUE

事件属性是枚举值可以比较他们的枚举值:

select * from MyEvent where enumProp=EnumClass.ENUM_VALUE_1

另外,类中可以声名静态的方法,如枚举类EnumClass如下:

select * from MyEvent where enumProp=EnumClass.valueOf('ENUM_VALUE_1')

如果您的应用程序不引入,通过配置枚举类的包,它必须指定类的包名。枚举类是内部类必须遵守CLR约定使用"+"。

例如:枚举类Color是MyEvent的内部类,在org.myorg包中可以引用如下所示:

select * from MyEvent(enumProp=org.myorg.MyEvent+Color.GREEN).std:firstevent()

实例方法也可能被调用事件实例指定一个流名称,如下所示:

select myevent.computeSomething() as result from MyEvent as myevent

链接的实例方法是支持的,如这个例子说明:

select myevent.GetComputerFor('books', 'movies').Calculate() as result from MyEvent as myevent

2.5.4参数化的类型

当你的getter方法​​或访问器成员返回一个类型,例如索引属性IEnumerable<MyEventData>或者映射属性IDictionary<String, MyEventData>,于是属性表达式可能通过参数类型引用属性

一个参数化类型的事件的属性例子是:

public class NewEmployeeEvent {
     public String Name { get; }
     public IEnumerable<EducationHistory> Education { get; }
     public IDictionary<String, Address> Addresses { get; }
}

此事件的有效属性表达式的示例如下所示:

select Name, Education, Education[0].Date, Addresses('home').Street   from NewEmployeeEvent

2.6.1概述

事件也可以被实现了System.Collection.IDictionary<String,Object> 接口的对象代表。Map事件的属性是map值,通过了System.Collection.IDictionary<String,Object>接口暴露的get方法访问。

Map事件类型是一个综合型的系统,它可以消除需要使用CLR类的事件类型,从而更容易在运行时改变的类型或从其他来源产生的类型信息.

一个给定的Map事件类型可以有一个或多个也是map类型的超类,它可用到在任何Map超类型上可用的所有属性类型。此外,在EPL内的任何地方,使用一个map超类的事件类型名称,任何map子型及它们的子型都匹配表达式。

你的应用程序在运行时通过配置操作UpdateMapEventType,可以添加属性到现有的Map事件类型中。map属性不会被更新或删除 ,只能添加属性,嵌套的属性也可以添加。运行时配置也允许删除map事件类型和添加新的类型的信息。

在您的应用程序配置map事件类型通过提供一个类型名称,类型名称可用于进一步的map事件类型定义,去指定属性类型或一个数组属性类型的类型名称。

一对多关系在Map事件类型中是通过数组表示,一个在Map事件类型中的属性可能是一个简单的数组,一个CLR 对象组或是一个map组。

引擎在EPRuntime接口中通过SendEvent(DataMap map, String eventTypeName)方法来执行Map事件。实例在map中表现为事件属性。Key值必须是字符串,引擎才能找到Pattern或者EPL指定的事件属性名。

引擎不会验证事件类型名称或值。你的应用程序应确保通过的对象作为事件属性匹配create schema 属性名和类型,或者在运行时配置事件类型信息或静态配置。

2.6.2 MAP属性

Map事件属性可以是任何类型。Map属性是CLR应用程序提供对象:

• 如前所述,属性是CLR应用程序对象可以通过嵌套,索引,映射和动态属性的语法查询。

• Map类型的属性可以嵌套任意深度,因此可以被用来表示复杂的域信息。嵌套,索引,映射和动态属性的语法,可以用来在Map或数组内查询。

为了使用Map事件,事件类型名称和属性名称和类型必须通过配置让引擎知道。请参见13.4.2节的例子,“System.Collection.Generic.IDictionary的代表事件”。

下面的代码片断创建和处理Map事件。它首先定义了一个CarLocationUpdateEvent事件类型:

var mapEvent = new Dictionary<string,object>();
mapEvent["carId"] = carId;
mapEvent["direction"] = direction;
epRuntime.SendEvent(mapEvent, "CarLocUpdateEvent");

CarLocUpdateEvent现在能用在EPL表达式中

select carId from CarLocUpdateEvent.win:time(1 min) where direction = 1

该引擎还可以通过嵌套属性的语法,查询CLR 对象在Map事件中的值。因此,Map事件,可用于聚合多个数据结构到一个简单事件,时行方便的综合信息查询。下面的例子演示Map事件与account 对象。

var mapEvent = new Dictionary<string,object>();
mapEvent["txn"] = txn;
mapEvent["account"] = account;
epRuntime.SendEvent(mapEvent, "TxnEvent");

2.6.3 MAP父类

你的Map事件类型可以声明一个或多个超类型,在引擎初始化时或运行时,通过管理界面配置。

Map事件类型的超类,也必须是Map事件类型。父类所有属性名称和类型也可在子类中重载。此外,在EPL中,一个Map超类的事件类型名称用被应用,任何子类表达式也相匹配(类似于CLR 接口的概念)。

这个例子假定BaseUpdate事件类型已经声明,且作为一个AccountUpdate事件类型的超类(两个都是Map事件类型):

epService.EPAdministrator.GetConfiguration().
AddEventType("AccountUpdate", accountUpdateDef,new String[] {"BaseUpdate"});

你的应用程序EPL表达式中可能会选择BaseUpdate事件,会收到BaseUpdate和

AccountUpdate事件,以及BaseUpdate的任何其它子类。

select * from BaseUpdate

你的应用程序Map事件类型可能有多个超类。多重继承层次结构之间的MAP可以任意深度,但是循环依赖是不允许的。如果使用运行时配置,增加子类时,必须父类先存在。

2.6.4 MAP高级属性类型

嵌套属性:

强壮的类型嵌套的map事件可以被用来建立丰富,类型安全的事件类型。使用AddEventType方法配置在初始化时或运行时定义的类型。值得注意的地方:

• CLR 的对象(POCO),可以作为属性出现在MAP嵌套中。

• 一个Map中便用的事件类型名称可能代表一个Map嵌套,或者Map嵌套数组.

• 嵌套的级别没有限制

• 动态属性,可以用来查询Map内可能无法预先知道的key.

• 在嵌套结构的访问路径后面不能映射不存在的实体,该引擎返回的属性为null。

一对多关系:

对在map内模型重复的属性,你可以使用Map的属性数组。你可以使用原始类型的数组或CLR 对象的数组或一个先前定义的Map事件类型的数组.

当使用先前宣布的Map事件类型作为一个数组属性,literal[]必须追加在事件类型名称后。.

下面的例子定义了一个名称Sale的Map事件类型,拥有各类型的数组属性。它假定SalesPerson 的CLR 类存在和OrderItem的被声明为一个Map事件类型:

Map<String, Object> sale = new HashMap<String, Object>();
sale["userids"] = typeof(int[]);
sale["salesPersons"] = typeof(SalesPerson[]);
sale["items"] = "OrderItem[]"; // The property type is the name itself appended by []
epService.EPAdministrator.GetConfiguration().
AddEventType("SaleEvent", sale);

 

上面的例子中声明的三种属性:

• 整数类型数组userid

• 对象数组 SalesPerson

• Map类型数组 orderitems.

下来的EPL声明对数组属性值查询的示例:

select userids[0], salesPersons[1].name,items[1], items[1].price.amount from SaleEvent

posted @ 2013-03-02 10:05  张善友  阅读(1694)  评论(0编辑  收藏  举报