我想汇总一天中每小时的传感器值。时间信息来自事件流中的时间戳。为此,我创建了四个EPL语句:
我每2-6秒接收大约300个传感器的事件。我将esper 6.1.0嵌入到堆大小为8 GB的Java应用程序中。大约15分钟后,内存压力使得垃圾收集进入过载状态,导致应用程序无法使用。如果我删除了最后一个EPL语句,我的应用程序会再次正常运行。
我对这种行为感到有些困惑。我认为当使用上下文时,esper不会在内存中累积事件。
所以我的问题是:使用EPL,我如何执行简单的聚合(例如总和,平均),使内存消耗 O(n)而不是 O(n * t),其中 n 是传感器的数量,而 t 是时间窗口的长度? < / p>
具体来说,这是我的EPL陈述。
声明1:
create context ctxPartitionById partition by sensorId from SensorEvent
声明2:
context ctxPartitionById
INSERT INTO HourChanged
SELECT
E.sensorId as sensorId,
prev(1, E.occurredAtHour) AS lastHour,
E.occurredAtHour AS currentHour
FROM SensorEvent#length(2) E
WHERE E.occurredAtHour != prev(1, E.occurredAtHour)
陈述3:
create context ctxPartitionByIdAndHour
context PartitionedByKeys
partition by
sensorId, currentHour from HourChanged,
sensorId, occurredAtHour from SensorEvent,
context InitiateAndTerm
initiated by HourChanged as e1
terminated by HourChanged(sensorId=e1.sensorId and lastHour=e1.currentHour)
陈述4:
context ctxPartitionByIdAndHour
SELECT
E.sensorId,
E.occurredAtHour,
SUM(E.value) AS sensorValueSum
FROM SensorEvent E
output last when terminated
sensorId
是实现Comparable
的java类的实例。
occurredAtHour
是java.util.Date
个实例。它的值是一个已经向下舍入到小时的时间戳。
value
是double
。
答案 0 :(得分:0)
键控上下文不会忘记分区。所以你做“通过sensorId进行分区,来自HourChanged的currentHour,来自SensorEvent的sensorId,happenAtHour”,因为这是一个键控上下文(在顶部)分区键保持不变,因为引擎认为你总是在寻找下一个HourChanged事件。同样的关键。这意味着引擎会记住“sensorId”和“currentHour”的每种可能组合。所以这可能不是你想要的。有关此问题的提示位于解决方案模式页面中。
对于语句4,输出速率限制可能导致事件保留在内存中,因为默认情况下引擎会在终止时计算输出。请注意select子句如何选择事件属性。当您选择事件属性时,这些属性来自实际事件。相反,你可以简单地将它作为一个完全聚合的查询,因此它没有理由保留任何事件。
context ctxPartitionByIdAndHour
SELECT last(E.sensorId), last(E.occurredAtHour), SUM(E.value) AS sensorValueSum
FROM SensorEvent E
output last when terminated
您可以在解决方案模式中执行类似操作。 http://espertech.com/esper/solution_patterns.php#absence-11 http://espertech.com/esper/solution_patterns.php#semantic-window-2
答案 1 :(得分:0)
将@Hint('enable_outputlimit_opt')
添加到第四个和最后一个EPL语句可以解决问题。
当使用output last
时,显然esper会将事件保留在内存中,除非存在此特定提示。请参阅esper文档中的5.7.3. Runtime Considerations。