Esper中的会话窗口(上下文)

时间:2018-06-15 07:53:28

标签: esper

我正在寻找一种在动态窗口中对Esper事件进行分组或窗口化的方法,类似于Apache Flink调用会话窗口(见下文)

Session Windows

我想为每个会话创建一个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;

Esper EPL Online

的一些测试数据
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中创建(动态)会话窗口(或上下文)?

2 个答案:

答案 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))