Esper: detect event start only - esper

I'm new to Esper (NEsper, actually) and I've been trying (unsuccesfully) to create an statement to detect when an event starts.
For example, suppose I have an event type called "Started betting" and I want to consider it is happening after 10 minutes of having "proof" of that. With what I've been using as the statement, after 10 minutes the update() method is triggered every time there is "proof".
I've tried something like
from (...), StartedBetting as st
where st is null AND (...)
but didn't work (event was never detected).
Hope I've made myself clear.
Any hints will be appreciated.

So if I understand you right, when receiving any start-betting event you simply want to delay for 10 minutes and then get called? The "proof" part is not clear. But this would do it:
select * from pattern [every StartBetting -> timer:interval(10 min)]

Related

Count how many times esper receives different inherit events.

I'm new using Esper and I have been able to manage with it until now. There is something that I can't find solution and I have tried to find everywhere with no success.
I have three Classes extending one to other one.
Using Esper Online:
create schema A(symbol string, price double);
create schema B() inherits A;
create schema C() inherits B;
Now I want to count how many of each events in a time window of 2 seconds I have received, using the next EPL statement:
select COALESCE(a.symbol,b.symbol,c.symbol) as symbol, count(a) as total_a, count(b) as total_b, count(c) as total_c from pattern [every a=A or every b=B or every c=C]#time(2 seconds) group by COALESCE(a.symbol,b.symbol,c.symbol);
And I run the next events:
A={symbol='X', price=1}
B={symbol='X', price=1}
C={symbol='X', price=1}
C={symbol='X', price=1}
The problem is when I send a B event, it counts a B event and an A event due to inheritance , and obviously if I send a C event it counts a C a B and also an A event.
I have used the pattern-level annotation #SuppressOverlappingMatches it works with inheritances, but Time Windows doesn't work with it.
Try this.
select count(*, typeof(a)='A') as cnt_a, count(*, typeof(a)='B') as cnt_b,
count(*, typeof(a)='C') as cnt_c from A#time(2 sec) as a

Esper very simple context and aggregation

I have a quite simple problem to modelize and I don't have experience in Esper, so I may be headed the wrong way so I'd like some insight.
Here's the scenario: I have one stream of events "ParkingEvent", with two types of events "SpotTaken" and "SpotFree". So I have an Esper context both partitioned by id and bordered by a starting event of type "SpotTaken" and an end event of type "SpotFree". The idea is to monitor a parking spot with a sensor and then aggregate data to count the number of times the spot has been taken and also the time occupation.
That's it, no time window or whatsoever, so it seems quite simple but I struggle aggregating data. Here's the code I got so far:
create context ParkingSpotOccupation
context PartionBySource
partition by source from SmartParkingEvent,
context ContextBorders
initiated by SmartParkingEvent(
type = "SpotTaken") as startEvent
terminated by SmartParkingEvent(
type = "SpotFree") as endEvent;
#Name("measurement_occupation")
context ParkingSpotOccupation
insert into CreateMeasurement
select
e.source as source,
"ParkingSpotOccupation" as type,
{
"startDate", min(e.time),
"endDate", max(e.time),
"duration", dateDifferenceInSec(max(e.time), min(e.time))
} as fragments
from
SmartParkingEvent e
output
snapshot when terminated;
I got the same data for min and max so I'm guessing I'm doing somthing wrong.
When I'm using context.ContextBorders.startEvent.time and context.ContextBorders.endEvent.time instead of min and max, the measurement_occupation statement is not triggered.
Given that measurements have already been computed by the EPL that you provided, this counts the number of times the spot has been taken (and freed) and totals up the duration:
select source, count(*), sum(duration) from CreateMeasurement group by source

Is Neo4j newsfeed flawed?

I am using this example, http://neo4j.com/docs/stable/cypher-cookbook-newsfeed.html, to maintain newsfeeds for my users. So I use the following to post a status update:
MATCH (me)
WHERE me.name='Bob'
OPTIONAL MATCH (me)-[r:STATUS]-(secondlatestupdate)
DELETE r
CREATE (me)-[:STATUS]->(latest_update { text:'Status',date:123 })
WITH latest_update, collect(secondlatestupdate) AS seconds
FOREACH (x IN seconds | CREATE (latest_update)-[:NEXT]->(x))
RETURN latest_update.text AS new_status
I encountered a severe flaw in this and don't know how to fix it. In a very rare scenario where two status updates are posted at the exactly same time (ex. 10ms apart), instead of replacing the current status, Neo4j creates two status updates. This leads to a much bigger problem where, the next updates are posted twice!
This looks like a race condition. To resolve that you basically need to make sure that at a given time only one transaction is modifying the status for this specific user.
Neo4j's Java API does have the ability to set locks to achieve this. Cypher doesn't have an explicit feature for this but you can e.g. remove a non-existing property to force a lock on the given node. With a lock in place concurrent transaction need to wait this the holder of the lock is finished with his transaction.
So grab a lock early in your statement:
MATCH (me)
WHERE me.name='Bob'
REMOVE me._not_existing // side effect: grab a lock early
WITH me
OPTIONAL MATCH (me)-[r:STATUS]-(secondlatestupdate)
DELETE r
CREATE (me)-[:STATUS]->(latest_update { text:'Status',date:123 })
WITH latest_update, collect(secondlatestupdate) AS seconds
FOREACH (x IN seconds | CREATE (latest_update)-[:NEXT]->(x))
RETURN latest_update.text AS new_status

Esper EPL statement each time a value has increased a multiple

I am looking for an EPL statement which fires an event each time a certain value has increased by a specified amount, with any number of events in between, for example:
Considering a stream, which continuously provides new prices.
I want to get a notification, e.g. if the price is greater than the first price + 100. Something like
select * from pattern[a=StockTick -> every b=StockTick(b.price>=a.price+100)];
But how to realize that I get the next event(s), if the increase is >= 200, >=300 and so forth?
Diverse tests with context and windows has not been successful so far, so I appreciate any help! Thanks!
The contexts would be the right way to go.
You could start by defining a start event like this:
create schema StartEvent(threshold int);
And then have context that uses the start event:
create context ThresholdContext inititiated by StartEvent as se
terminated after 5 years
context ThresholdContext select * from pattern[a=StockTick -> every b=StockTick(b.price>=context.se.threshold)];
You can generate the StartEvent using "insert into" from the same pattern (probably want to remove the "every") or have the listener send in a StartEvent or declare another pattern that fires just once for creating a StartEvent.

Forcing output in Esper

I have a non real time Esper configuration where I feed a stream that I read from a file. I'm trying to create an expression that computes a statistic over the entire stream and outputs one value at the very end. Esper has semantics for forcing a view to output every X seconds, for instance, but is there a semantic for asking the view or the engine to "flush" the output when you know there are no more events to feed.
Turns out that at least one way to do this is to use the output clause with a variable trigger.
The expression would be:
select count(*) as totalCount from events output last when OutputSummary = true
The OutputSummary variable would be initialized like so:
epConfiguration.addVariable("OutputSummary", Boolean.class, "false");
When you're ready to flush, set the variable to true like so:
epRuntime.setVariableValue("OutputSummary", true);
long currentTime = epService.getEPRuntime().getCurrentTime();
epRuntime.sendEvent(new CurrentTimeEvent(currentTime));
It's necessary to send another time event to force the expression to evaluate.
When output requires at every 60 sec then the expression would be:
select emplyee_id from employees output snapshot every 60 sec
and when the output requires at every 10000 events then the expression would be:
select emplyee_id from employees output snapshot every 10000 events

Resources