我正在寻找一种在动态窗口中对Esper事件进行分组或窗口化的方法,类似于Apache Flink调用会话窗口(见下文)
我想为每个会话创建一个Contex,但到目前为止还无法完成捕获会话的方法。初始(不工作)示例;
CREATE SCHEMA EventX AS (sensorId string, timestamp long, value double);
CREATE SCHEMA SessionEvent AS (sensorId string, totalValue double, events EventX[]);
-- Unsure about Context definition
CREATE CONTEXT sensorSessionCtx
CONTEXT sensorCtx PARTITION BY sensorId FROM EventX,
CONTEXT sessionCtx INITITATED BY Eventx TERMINATED BY pattern [every EventX -> (timer:interval(3 sec) and not EventX)];
CONTEXT sensorSessionCtx
INSERT INTO SessionEvent
SELECT sensorId
, SUM(value) AS totalValue
, window(*) AS events
FROM EventX#keepall
OUTPUT LAST WHEN TERMNATED;
@Name('Sessions') SELECT * FROM SessionEvent;
的一些测试数据
EventX = {sensorId='A', timestamp=0, value=1.1}
t=t.plus(1 seconds)
EventX = {sensorId='A', timestamp=1000, value=3.2}
t=t.plus(1 seconds)
EventX = {sensorId='B', timestamp=2000, value=8.4}
t=t.plus(1 seconds)
EventX = {sensorId='A', timestamp=3000, value=2.7}
EventX = {sensorId='B', timestamp=3000, value=0.2}
t=t.plus(3 seconds)
EventX = {sensorId='A', timestamp=6000, value=3.1}
预期产出;
SessionEvent={sensorId='A', totalValue=7.0, events={[EventX={sensorId='A', timestamp=0, value=1.1},EventX={sensorId='A', timestamp=1000, value=3.2},EventX={sensorId='A', timestamp=3000, value=2.7}]}}
SessionEvent={sensorId='B', totalValue=8.6, events={[EventX={sensorId='B', timestamp=2000, value=8.4},EventX={sensorId='B', timestamp=3000, value=0.2}]}}
SessionEvent={sensorId='A', totalValue=3.1, events={[EventX={sensorId='A', timestamp=6000, value=3.1}]}}
我如何在Esper中创建(动态)会话窗口(或上下文)?
答案 0 :(得分:0)
也可以这样做。
CREATE CONTEXT sensorSessionCtx
initiated by distinct(sensorId) EventX as ex
terminated by pattern [every (timer:interval(3 sec) and not EventX(sensorId=ex.sensorId))];
CONTEXT sensorSessionCtx
SELECT sensorId
, SUM(value) AS totalValue
, window(*) AS events
FROM EventX(sensorId=context.ex.sensorId)#keepall
OUTPUT WHEN TERMiNATED;
这现在忘记了" sensorId"如果您的sensorId值的空间是无穷无尽的,那么这些值很有用。否则,如果您通过sensorId"进行分区。这意味着引擎始终跟踪所有sensorIds。
不需要"从SessionEvent"中选择*所以我把它留了出来。
如果输出不需要包含事件,请删除#keepall,即CONTEXT sensorSessionCtx SELECT sensorId, sum(value) AS totalValue FROM EventX(sensorId=context.ex.sensorId) OUTPUT SNAPSHOT WHEN TERMINATED;
编辑: 应该是"每一个(定时器:间隔(3秒)而不是EventX(sensorId = ex.sensorId))"在终止。之前的建议是错误的,因为启动事件永远不会计入终止事件/模式(因此EventX - >每个(...)都是错误的。)
答案 1 :(得分:0)
要在Esper中提供会话上下文,我们需要创建Nested Context。
在这个嵌套的上下文中,我们首先定义Keyed Segment上下文,然后分割'根据示例流,流式传输到单独的用户或传感器。然后我们定义第二个Non-Overlapping上下文。第二个上下文仅在第一个键控上下文中运行(因此此上下文中的所有事件都具有相同的 sensorId )。
CREATE CONTEXT sensorSessionCtx
CONTEXT sensorCtx
PARTITION BY sensorId FROM EventX
, CONTEXT sessionCtx
START EventX
END pattern [every (timer:interval(3 sec) AND NOT EventX)];
在该示例中,具有此上下文定义的输出将是;
At: 2001-01-01 08:00:06.000
Insert
SessionEvent={sensorId='A', totalValue=7.000000000000001, events={[EventX={sensorId='A', timestamp=0, value=1.1},EventX={sensorId='A', timestamp=1000, value=3.2},EventX={sensorId='A', timestamp=3000, value=2.7}]}}
Insert
SessionEvent={sensorId='B', totalValue=8.6, events={[EventX={sensorId='B', timestamp=2000, value=8.4},EventX={sensorId='B', timestamp=3000, value=0.2}]}}
At: 2001-01-01 08:00:09.000
Insert
SessionEvent={sensorId='A', totalValue=3.1, events={[EventX={sensorId='A', timestamp=6000, value=3.1}]}}
虽然注意到,当内部引擎计时器被禁用时,对于最后一个窗口终止,应该收到一个事件(任何类型都会),其时间戳大于上一个会话事件时间戳+ 会话差距。在EPL Online工具中,可以通过在最后定义的输入事件之后添加t=t.plus(10 seconds)
来完成此操作。如果您想创建任何类型的单元测试
val finalEventTimestamp = Long.MaxValue - 1 //Note: Long.MaxValue won't trigger final evaluation!
engine.getEPRuntime.sendEvent(new CurrentTimeEvent(finalEventTimestamp))