2.1。介绍
第J.11节“.NET基本概念”
。
语句是连续查询,用于分析事件和时间以及检测情境。
您通过编译和部署包含语句的模块,通过发送事件和提前时间以及通过回调接收输出或轮询当前结果来与Esper交互。
表2.1。
与Esper交互
什么
|
怎么样
|
---|---|
EPL
|
首先,编译和部署语句,请参阅
第5章,
EPL参考:子句
,
第15章,
编译器参考
和
第16章,
运行时参考
。
|
回调
|
其次,附加应用程序提供的可执行代码以接收输出,请参阅
表16.2“接收语句结果的选择”
。
|
活动
|
接下来,使用运行时API发送事件,请参见
第16.6节“使用EPEventService处理事件和时间”
。
|
时间
|
接下来,使用运行时API或系统时间的提前时间,请参见
第16.9节“控制时间保持”
。
|
运行时包含如下语句:
第4章,
上下文和上下文分区
。
未隐式分区的语句具有一个分区。
部署未分区语句后,运行时将分配单个分区。
取消部署未分区的语句后,运行时会破坏分区。
分区(或
上下文分区
)是运行时保持状态的位置。
在上图中,有三个未分区的语句和一个具有三个分区的分区语句。
接下来的部分将讨论各种易于理解的陈述。
这些部分说明了语句的行为方式,运行时传递给回调的信息(输出)以及运行时为语句记住的信息(
状态
,所有状态都存在于分区中)。
示例语句假定
Withdrawal
具有
account
和
amount
属性的
名称的事件类型
。
2.2。基本选择
Withdrawal
事件。
从提款中选择*复制代码
Withdrawal
事件到达时,运行时将到达事件(未更改且相同的对象引用)传递给回调。
之后,运行时会有效地忘记当前事件。
Withdrawal
随时间推移
的
事件(1到6)。
在图片中,
W
n
代表
Withdrawal
到达
的特定
事件。
括号中的数字是提款金额。
对于此语句,运行时不会记住任何信息,也不记得任何事件。
运行时根本不需要记住任何信息的语句是没有状态的语句(
无状态
语句)。
术语
插入流
是到达的新事件流的名称。
此示例中的插入流是到达提取事件的流。
2.3。基本聚合
第10.2节“聚合函数”
。
此语句选择所有提款事件的计数和总数。
从提款中选择计数(*),总和(金额)复制代码
在新
Withdrawal
事件到达时,运行时会增加计数并将金额添加到运行总计中。
它将新计数和总计传递给回调。
之后,运行时会有效地忘记当前事件,并且根本不记得任何事件,但会记住当前计数和总计。
这里,运行时只记住当前事件数和总量。
count是单个long-type值,total是单个double-type值(假设
amount
是double值,total可以是
BigDecimal
适用的)。
该语句不是无状态的,状态由长类型值和双类型值组成。
在新
Withdrawal
事件到达时,运行时将计数增加1并将该数量添加到运行总计中。
运行时不会重新计算计数和总数,因为它不记得事件。
通常,运行时不会重新计算聚合(除非另有说明)。
相反,运行时将数据添加(递增,输入,累积)到聚合状态,并从聚合状态中减去(递减,移除,减少,减少)。
2.4。基本过滤器
第5.4.1节“基于过滤器的事件流”
。
此语句选择
Withdrawal
金额为200或更高的事件:
select * from Withdrawal(金额> = 200)复制代码
在
Withdrawal
到达量为200或更高
的新
事件时,运行时将到达事件传递给回调。
对于此语句,运行时不会记住任何信息,也不记得任何事件。
你可能会问,对于
Withdrawal
数量少于200的事件
会发生什么
。答案是声明本身甚至看不到这样的事件。
这是因为运行时知道立即丢弃此类事件,并且该语句甚至不知道此类事件。
运行时通过语句分析,计划和适当的数据结构非常快速地丢弃不需要的事件。
2.5。基本过滤和聚合
Withdrawal
金额为200或更高的事件
的计数和总金额
:
从提款中选择计数(*),总和(金额)(金额> = 200)复制代码
Withdrawal
到达量为200或更高
的新
事件时,运行时会增加计数并将金额添加到运行总计中。
运行时将计数和总数传递给回调。
在此示例中,运行时仅记住计数和总计,并且再次不记住事件。
运行时丢弃
Withdrawal
的数量小于200的事件。
2.6。基本数据窗口
数据窗口
,或
窗口
的简称,保存用于聚合的目的活动,加入,匹配识别模式,子查询,经由API和输出快照迭代。
数据窗口定义要保留的事件子集。
例如,长度窗口保留最后N个事件,时间窗口保持最后N秒事件。
有关
详细信息
,
此语句选择所有
Withdrawal
事件并指示运行时记住最后五个事件。
select * from Withdrawal #length(5)复制代码
在新
Withdrawal
事件到达时,运行时将事件添加到长度窗口。
它还将相同的事件传递给回调。
在事件W
6
到达时
,事件W
1
离开长度窗口。
我们使用术语
expires
来表示事件离开数据窗口。
我们使用术语
删除流
来描述离开数据窗口的事件流。
运行时总共记住最多五个事件(最后五个事件)。
在语句开头,数据窗口为空。
保持最后五个事件本身可能听起来不太有用。
但是,与连接,子查询或匹配识别模式相关联,例如数据窗口告诉运行时您要查询哪些事件。
2.7。基本数据窗口和聚合
Withdrawal
事件
的计数和总数
。
从提款中选择计数(*),总和(金额)#长度(5)复制代码
Withdrawal
事件到达时,运行时将事件添加到长度窗口,将计数增加1并将该量添加到当前总量。
当
Withdrawal
事件离开数据窗口时,运行时将计数减1,并从当前总量中减去其数量。
它将运行计数和总数传递给回调。
在事件W
6
到达之前,
当前计数为5,并且运行总量为1000.在事件W
6
到达时,发生
以下情况:
-
运行时确定事件W1离开长度窗口。
-
为了考虑新事件W6,运行时将计数增加1并将运行总量加300。
-
为了考虑到期事件W1,运行时将计数减1并从运行总量中减去500。
-
输出结果为5,结果总计为800
1000 + 300 - 500
。
运行时添加(递增,输入,累积)插入流事件到聚合状态,并减去(递减,删除,减少,减少)从聚合状态中删除流事件。
因此,它以递增的方式维护聚合状态。
对于此声明,一旦计数达到5,计数将始终保持为5。
运行时为此语句记住的信息是最后五个事件以及当前的长类型计数和双类型总计。
小费
使用
irstream
关键字接收聚合语句的当前聚合值和先前聚合值。
2.8。基本过滤器,数据窗口和聚合
Withdrawal
仅考虑那些
Withdrawal
数量至少为200的事件,
输出最近五个
事件
的计数和总数
:
从提款中选择计数(*),总和(金额)(金额> = 200)#length(5)复制代码
Withdrawal
事件到达时,并且仅当该提取事件具有200或更多的量时,运行时将事件添加到长度窗口,将计数增加1并将该量添加到当前总量。
当
Withdrawal
事件离开数据窗口时,运行时将计数减1,并从当前总量中减去其数量。
它将运行计数和总数传递给回调。
2.9。基本的Where-Clause
....
意味着任何select子句表达式)
,以下两个语句完全等效
:
选择....从提款(金额> 200)
// 相当于
选择....从提款金额> 200复制代码
第5.5节“指定搜索条件:Where子句”
中有更详细的讨论
。
select * from Withdrawal#length(5)其中amount> = 200复制代码
where子句适用于新事件和到期事件。
只有传递where子句的事件才会传递给回调。
2.10。基本时间窗口和聚合
第14.3.3节“时间窗口(时间或获胜:时间)”
。
Withdrawal
考虑到事件的最后四秒,
下一个语句选择
事件
的计数和总量
。
选择计数(*),总和(金额)作为提取的总数#time(4)复制代码
该图开始于一个给定的时间
t
,并在显示时间窗口中的内容
t + 4
和
t + 5 seconds
等。
活动如图所示:
-
在
t + 4 seconds
事件到达时,输出计数为1,总计为500。W1
-
在
t + 5 seconds
事件到达时,输出计数为2,总计为600。W2
-
在
t + 6.5 seconds
事件到达时,输出为三个,总计为800。W3
-
在时间
t + 8 seconds
事件到期并且输出是2的计数和总计300。W1
对于此语句,运行时会记住
Withdrawal
事件
的最后四秒
以及长类型计数和双重类型总计。
小费
时间可以有毫秒或微秒的分辨率。
2.11。基本分区声明
第4章“
上下文和上下文分区”
。
我们将有一个立即启动并在四秒后结束的分区:
创建上下文Batch4Seconds在4秒后开始@now结束复制代码
接下来的语句选择的数量和总金额
Withdrawal
自上次复位(复位是在那个赶到活动
t
,
t+4
,
t+8
如等等),重置每4秒:
context Batch4Seconds从提取中选择count(*),total(amount)复制代码
在时间
t + 4 seconds
和
t + 8 seconds
运行时会破坏当前分区。
这会丢弃当前计数和运行总计。
运行时立即分配一个新分区,计数和总开始时间为零。
对于此语句,运行时仅记住计数和运行总计,以及分区的生存时间。
2.12。基本产出率限制声明
第5.7节“稳定和控制输出:输出子句”中所述
。
下一个语句
Withdrawal
每四秒
输出最后一次计数和所有
事件的
总数
:
每4秒从提取输出中选择计数(*),总数(金额)复制代码
在时间
t + 4 seconds
和
t + 8 seconds
运行时将最后的聚合值输出到回调。
对于此语句,运行时仅记住计数和运行总计,以及输出发生时的事实。
2.13。基本分区和输出率限制声明
Withdrawal
四秒结束时最后四秒内到达
的
事件
的计数和总数
,在输出后重置:
创建上下文Batch4Seconds在4秒后开始@now结束复制代码
context Batch4Seconds选择count(*),从终止时的提取输出中获取的总数(金额)复制代码
在时间
t + 4 seconds
和
t + 8 seconds
运行时将最后的聚合值输出到回调,并重置当前计数和总计。
对于此语句,运行时仅记住计数和运行总计,以及输出发生时的事实以及分区的生存时间。
2.14。基本命名的Windows和表
第6章,
EPL参考:命名的Windows和表
。
可以通过API以及面向内部的JDBC驱动程序查询命名窗口和表格,使用“即发即弃”查询。
2.14.1。命名为Windows
from
-clause
中具有命名窗口名称的其他语句
隐式聚合或分析同一组事件。
这消除了为不同的EPL语句多次声明相同窗口的需要。
步骤#1
创建一个命名窗口,如下所示:
创建窗口取款窗口#time(10)作为提款复制代码
命名窗口的名称是
WithdrawalWindow
,它将保存最后10秒的
Withdrawal
事件(
#time(10) as Withdrawal
)。
作为步骤#1的结果,运行时分配一个命名窗口来保存10秒的
Withdrawal
事件。
在图形中,命名窗口充满了一些事件。
通常,一个命名窗口以一个空窗口开始,但它看起来更好,内部已有一些盒子。
步骤#2
创建一个EPL语句以插入到命名窗口中:
on Withdrawal merge WithdrawalWindow insert select *复制代码
这告诉运行时,在
Withdrawal
事件
到达时
它必须
WithdrawalWindow
与插入事件
合并
。
运行时现在等待
Withdrawal
事件到达。
步骤#3
创建一个EPL语句,该语句计算由命名窗口控制的事件子集的平均提取量:
从WithdrawalWindow中选择avg(amount)作为avgAmount复制代码
作为步骤#3的结果,运行时分配状态以保持当前平均值。
状态由
count
字段和
sum
字段
组成,
用于计算运行平均值。
它确定命名窗口当前为空并将其设置
count
为零并且设置
sum
为null(如果命名窗口已经填充,则它将确定
count
并
sum
通过迭代)。
在内部,它还使用命名窗口注册消费者回调,以接收插入和删除的事件(插入和删除流)。
回调在图中显示为虚线。
在步骤#4中,
假设
Withdrawal
到达具有帐号
0001
和金额的事件
5000
。
运行时执行
on Withdrawal merge WithdrawalWindow insert select *
并因此将事件添加到时间窗口。
运行时为所有使用者调用插入流回调(虚线,内部管理的回调)。
计算平均金额的消费者接收回调和新插入的事件。
它将
count
字段
增加
1并增加
sum
字段
5000
。
声明的输出
avgAmount
为
5000
。
在步骤#5中
,在步骤#4之后10秒
Withdrawal
发生,帐户
0001
和金额
的
事件
5000
离开时间窗口。
运行时为所有使用者调用删除流回调(虚线,内部管理的回调)。
计算平均金额的消费者会收到回调和新删除的事件。
它减少了
count
一个字段并将
sum
以
null
和
count
是零。
声明的输出
avgAmount
为
null
。
2.14.2。表
window
和
sorted
聚合)或count-min-sketch(存储近似值的一组哈希表)。
您的应用程序可以轻松扩展并提供自己的聚合。
步骤#1
创建一个如下表格:
create table AccountAverages(帐户字符串主键,avgAmount avg(double))复制代码
已经表
string
-typed账户号码作为主键。
该表还有一个包含平均值
double
类型
的列
。
注意如何
create table
不需要知道平均值如何更新,它只需要知道平均值是平均值
double
类型。
作为步骤#1的结果,运行时分配表。
在图纸中,表格填充了两行,用于两个不同的帐号
0001
和
0002
。
通常,表以空表开始,但我们假设表已经有了行。
为了存储平均值的双精度值,运行时必须保持计数和总和。
因此,在
avgAmount
该表的列有字段的
count
和
sum
。
对于账户
0001
假设目前还没有值,并且
count
是零和
sum
IS
null
。
步骤#2
创建一个EPL语句,聚合提取事件的最后10秒:
进入表AccountAverages
选择avg(amount)作为avgAmount
来自退出#time(10)
按帐户分组复制代码
在
into table
本地没有告诉编译器来存储聚合作为语句的一部分,但到
AccountAverages
表代替。
该
as avgAmount
告诉编译器使用的列
avgAmount
在表中。
编译器检查聚合类型和值类型是否与表列匹配,并且
group by
-clause与表主键匹配。
运行时查找
Withdrawal
事件并保持10秒的时间窗口。
通常,时间窗口以空时间窗口开始,但图形显示时间窗口中的一些事件。
在步骤#3中,
假设
Withdrawal
事件到达,其帐号
0001
和金额为
5000
。
运行时将事件添加到时间窗口。
运行时更新
avgAmount
表
的
列,特别是两个字段
count
和
sum
。
它将
count
字段
增加
1并增加
sum
字段
5000
。
在帐号的行不存在的情况下,运行时分配表行及其列和聚合字段。
在步骤#3
之后10秒发生的步骤#4中,
Withdrawal
帐户
0001
和金额
的
事件
5000
离开时间窗口。
运行时更新
avgAmount
表
的
列。
它减少了
count
一个字段并将
sum
以
null
作为
count
为零。
其他EPL语句可以通过将表放入
from
-clause,或通过table-access-expression,on-action语句或fire-and-forget查询
来访问表列
。
2.15。基本聚合语句类型
第5.6.4节“为每个聚合函数指定分组”
。
该文档提供了
附录A,
输出参考和样本中
以下示例假定
BankInformationWindow
是在其他地方定义的命名窗口。
这些示例使用连接来说明。
第5.12节“加入事件流”
2.15.1。Un-Aggregated和Un-Grouped
select * from Withdrawal unidirectional,BankInformationWindow复制代码
Withdrawal
事件进入时,输出行数是该行中的行数
BankInformationWindow
。
A.2节“非聚合和非聚集语句的输出”中的
输入和输出事件
。
2.15.2。完全聚合和未分组
选择金额(金额)
来自提取单向,BankInformationWindow复制代码
Withdrawal
事件进入时,输出行的数量始终为零或一。
第A.3节“完全聚合和未分组语句的输出”中的
输入和输出事件
。
group_by
例如
sum(amount, group_by:account)
,
如果任何聚合函数指定
参数和维度
,则该语句将作为聚合和分组语句执行。
2.15.3。聚合和非聚集
选择帐户,总和(金额)
来自提取单向,BankInformationWindow复制代码
Withdrawal
事件进入时,输出行数是该行中的行数
BankInformationWindow
。
A.4节“聚合和非分组语句的输出”中的
输入和输出事件
。
2.15.4。完全聚合和分组
select
子句中的
所有非聚合属性
都列在
group by
子句中,那么您的语句可能类似于此示例:
选择帐户,总和(金额)
来自提取单向,BankInformationWindow
按帐户分组复制代码
Withdrawal
事件进入时,每个唯一帐号的输出行数为一行。
第A.5节“完全聚合和分组语句的输出”中的
输入和输出事件
。
例如,如果任何聚合函数指定
group_by
参数和维度以外的
group by
维度
sum(amount, group_by:accountCategory)
,则该语句将作为聚合和分组语句执行。
2.15.5。聚合和分组
group by
子句对
某些属性进行分组
,则您的语句可能如下所示:
选择帐户,帐户名,总和(金额)
来自提取单向,BankInformationWindow
按帐户分组复制代码
Withdrawal
事件进入时,输出行数是该行中的行数
BankInformationWindow
。
第A.6节“聚合和分组语句的输出”中
2.16。基本匹配识别模式
从AlertNamedWindow中选择*
match_recognize(
按来源划分
测量a1.origin为原点,a1.alarmNumber为alarmNumber1,a2.alarmNumber为alarmNumber2
模式(a1 a2)
限定
a1 as a1.priority ='high',
a2 as a2.priority ='medium'
)复制代码
2.17。基本的EPL模式
每个StockTickEvent(符号=“IBM”,价格> 80)其中计时器:在(60秒)内复制代码
每个计时器:at(5,*,*,*,*)复制代码
A - >(B或C)复制代码
每个a = EventX - >每个b = EventY(objectID = a.objectID)复制代码
2.18。基本索引
2.18.2。过滤索引
过滤器
或
过滤条件
来表示选择谓词,例如
symbol=“google” and price > 200 and volume > 111000
。
语句在
from
-clause和/或EPL模式和/或上下文声明中
提供过滤条件
。
请参见
第5.4.1节“基于过滤器的事件流”
,
第7.4节“模式中的过滤器表达式”
和
第4.2.7.1节“过滤上下文条件”
。
Big-O表示法缩放信息可以在
第23.1.1节“匹配事件到语句和上下文分区的大O复杂性”中找到
。
当运行时接收到事件时,它会查询过滤器索引以确定哪些语句(如果有)必须处理该事件。
过滤索引的目的是启用:
-
事件的有效匹配仅适用于那些需要它们的语句。
-
高效丢弃任何声明不需要的事件。
-
最佳情况下的有效评估大约为O(1)到O(log n),即在最佳情况下,在大致相同的时间内执行,而不管输入数据集的大小是有效滤波器的数量。
过滤器索引构建是编译器分析
from
-clause和EPL模式中
的过滤条件的结果
。
它由运行时自动完成。
当在
from
-clause或pattern中
发生此类事件类型时,运行时为每个事件类型构建和维护单独的过滤器索引集
。
筛选索引在同一事件类型筛选器中是可共享的。
因此
from
,引用相同事件类型的
各种
-clauses和模式可以贡献于同一组过滤器索引。
运行时以嵌套方式构建过滤器索引:过滤器索引可能包含更多过滤器索引,形成树状结构,过滤器索引树。
索引的嵌套超出了此处提供的介绍性讨论。
2.18.2.1。筛选索引多语句示例
from
声明中
的
-clause,在特殊情况下,
where
-clause
也
提供编译器分析的筛选条件,并为其构建筛选索引。
WithdrawalEvent
有一个
account
字段。
您可以创建三个语句,如下所示:
@name('A')select * from WithdrawalEvent(account = 1)复制代码
@name('B')从WithdrawalEvent(account = 1)中选择*复制代码
@name('C')从WithdrawalEvent(account = 2)中选择*复制代码
WithdrawalEvent
的是有一个事件
account
的声明1. I2C寄存器中的感兴趣的值
WithdrawalEvent
具有一个事件
account
的2值。
当
Withdrawal
事件到达时,运行时将提取
account
并执行上表中的查找。
如果表中没有匹配的行,例如当
account
为3时,运行时知道该事件没有进一步处理。
2.18.2.2。过滤索引模式示例
WithdrawalEvent
另一个
示例模式
:
WithdrawalEvent
account
@name('P')select * from pattern [every w1 = WithdrawalEvent - > w2 = WithdrawalEvent(account = w.account)]复制代码
WithdrawalEvent
事件。
目前只有一个有效过滤器:
WithdrawalEvent
W
a
到达。
然后运行时激活一个过滤器,
WithdrawalEvent
为帐户1
寻找另一个过滤器
。此时有两个活动过滤器:
WithdrawalEvent
W
b
到达。
然后运行时激活一个过滤器,
WithdrawalEvent
为帐户1
寻找另一个过滤器
。此时有三个活动过滤器:
WithdrawalEvent
W
c
到达。
然后运行时激活一个过滤器,
WithdrawalEvent
为帐户2
寻找另一个过滤器
。此时有四个活动过滤器:
a
,W
b
和W
c
事件到达
后模式的示例过滤器索引
:
当
Withdrawal
事件到达时,运行时将提取
account
并执行上表中的查找。
如果找到匹配的行,则运行时可以将事件切换到相关的模式子表达式。
2.18.2.3。过滤索引上下文示例
LoginEvent
有一个
account
字段。
您可以
LoginEvent
为用户
声明由a启动的上下文
:
@name('A')创建由LoginEvent作为loginEvent启动的上下文UserSession复制代码
LoginEvent
,例如:
@name('B')上下文UserSession从WithdrawalEvent中选择count(*)(account = context.loginEvent.account)复制代码
LoginEvent
事件。
目前只有一个有效过滤器:
LoginEvent
L
a
到达。
然后运行时激活语句B的上下文分区,因此过滤器查找
WithdrawalEvent
帐户1.此时有两个活动过滤器:
LoginEvent
L
b
到达。
然后运行时激活语句B的上下文分区,因此过滤器查找
WithdrawalEvent
帐户1.此时有三个活动过滤器:
LoginEvent
L
c
到达。
然后运行时激活语句B的上下文分区,因此过滤器查找
WithdrawalEvent
帐户2.此时有四个活动过滤器:
当
Withdrawal
事件到达时,运行时将提取
account
并执行上表中的查找。
然后,它可以将事件直接传递给相关的语句上下文分区,或者如果找不到给定帐户ID的行,则忽略该事件。
2.18.3。事件索引
第23.1.3节“连接的Big-O复杂性,子查询,On-Select,On-Merge,On-Update,On-Delete”中找到
。
由于事件索引与数据库索引类似,因此对于本讨论,我们使用术语
列
来表示EPL表或命名窗口中的列,并且还表示事件属性或字段。
我们使用术语
行
来表示EPL表或命名窗口中的行,也表示事件。
当运行时执行语句处理时,它可以使用事件索引来有效地查找相关行。
事件索引的目的是启用:
-
有效评估子查询。
-
有效评估连接。
-
有效评估行动声明。
-
有效评估即发即弃查询。
事件索引构建是编译器分析连接的
where-
子句关联条件(
on-
外连接子句),子查询,on-action和fire-and-forget查询的结果。
它由编译器自动完成。
您可以使用该
create index
子句显式索引命名的窗口和表。
您可以使用查询计划器提示来影响索引构建,使用和共享。
2.19。基本无效
true
和
false
,表达式的结果也可能是未知的。
三值逻辑是支持
null
标记缺失数据的结果。
如果
null
值影响逻辑表达式的结果,则结果既不是也不
true
是
false
未知。
null
值基本上意味着“可以是任何东西”。
因此,不可能讲的比较是否
null
是
true
或
false
。
这是第三个未知的逻辑值进入的地方。未知意味着“真或假,取决于空值”。
null
(未知):
null = 1复制代码
null <> 1复制代码
null> 1复制代码
null = null复制代码
等于
null。
甚至不
null
等于
null
因为每个
null
都可能不同。
这就是为什么EPL有
is null
谓词来测试值是否为空。