We describe work in progress on the design and implementation of an SQL-like language for performing complex queries on event streams. This language aims at providing a simple, intuitive and fully non-procedural syntax, while still preserving backwards compatibility with traditional SQL. The syntax and informal semantics of the language are introduced; multiple examples of scenarios taken from past literature are then presented, and used to compare the expressiveness and intuitiveness of the proposed language with respect to existing Complex Event Processing engines.
3. A processor is a function that takes 0 or more
event traces as input, and returns 0 or 1
event trace as output
. . . . . .
4. Processors can be composed: the output of
a processor can be given as the input of
another ("piping")
5. BeepBeep is an event stream query engine
that provides...
A set of basic processors (independent from
any event type)
A core grammar and interpreter to
compose ("pipe") processors
Mechanisms to extend the grammar
with user-defined events, processors, etc.
6. abc. . . a . . .
n c
Ψ
abc. . . b . . .
n c
EVERY nTH OF (T)
TRIM n FROM (T)
7. WHERE2 1 5 0 2 0
C
C2 1 5 0
(T) WHERE condition
8. COMBINE (T) WITH f
Σ+2 1 5 0 2 3 8
f
f
8
2 1 5 0 2 1 5 0
f1 5 0 1 5 0
f5 0 5 0
++
+
9. a . . .b
a . . .b
FILE "filename"
SAVE (T) TO "filename"
10. WHEN @P IS A PROCESSOR:
THE SUM OF ( @P )
IS THE PROCESSOR
COMBINE (@P) WITH SUM.
Arbitrary
symbol
Grammar rule this symbol
must parse against
New grammar case
Grammar rule the case
is added to
Expression the new case
stands for
11. WHEN @P IS A PROCESSOR:
THE COUNT OF ( @P ) IS THE PROCESSOR
COMBINE (SELECT 1 FROM (@P)) WITH SUM.
WHEN @P IS A PROCESSOR:
THE SUM OF ( @P ) IS THE PROCESSOR
COMBINE (@P) WITH SUM.
WHEN @P IS A PROCESSOR:
THE AVERAGE OF ( @P ) IS THE PROCESSOR
SELECT (T.*) ÷ (U.*) FROM (
THE SUM OF (@P) AS T,
THE COUNT OF (@P) AS U).
12. On every fifth trading day starting today,
calculate the average closing price of MSFT
for the five most recent trading days, and keep
the query standing for fifty trading days.
timestamp stockSymbol closingPrice
0 APPL 1039.3
0 MSFT 950.0
0 GOGL 433.3
1 MSFT 951.2
1 APPL 1038.3
... ... ...
13. On every fifth trading day starting today,
calculate the average closing price of MSFT
for the five most recent trading days, and keep
the query standing for fifty trading days.
String line = br.readLine().trim();
if (!line.isEmpty()) {
String[] parts = line.split(",");
if (parts[0].compareTo("ABC") != 0) {
value_index++;
sum += Double.parseDouble(parts[1]);
if (value_index == 5) {
double average = sum / 5;
value_index = 0;
sum = 0;
return average;
}}}
14. On every fifth trading day starting today,
calculate the average closing price of MSFT
for the five most recent trading days, and keep
the query standing for fifty trading days.
SELECT afd FROM (
SELECT S1.timestamp AS ts,
AVG(S2.closingPrice) AS afd
FROM
(SELECT * FROM stocks
WHERE stockSymbol = "MSFT") AS S1,
(SELECT * FROM stocks
WHERE stockSymbol = "MSFT") AS S2
WHERE (S2.timestamp - S1.timestamp) < 5
GROUP BY S1.timestamp) AS S3
WHERE MOD(ts, 5) = 0;
15. On every fifth trading day starting today,
calculate the average closing price of MSFT
for the five most recent trading days, and keep
the query standing for fifty trading days.
EVERY 5TH OF (
APPLY (THE AVERAGE OF (*)) TO (
SELECT closingPrice FROM stocks)
WHERE (stockSymbol) = ("MSFT"))))
ON A WINDOW OF 5).
16. Calculate how many times the closing price
of MSFT is greater than 20 and the next
day, its closing price is less than 10.
17. Calculate how many times the closing price
of MSFT is greater than 20 and the next
day, its closing price is less than 10.
SELECT COUNT(*) FROM
(SELECT * FROM stocks
WHERE stockSymbol = "MSFT") AS S1,
(SELECT * FROM stocks
WHERE stockSymbol = "MSFT") AS S2
WHERE (S2.timestamp - S1.timestamp) = 1
AND S1.closingPrice > 20
AND S2.closingPrice < 10;
18. Calculate how many times the closing price
of MSFT is greater than 20 and the next
day, its closing price is less than 10.
WHEN @P IS A PROCESSOR:
MY PATTERN IN ( @P ) IS THE PROCESSOR
(SELECT (closingPrice) LESS THAN (20) FROM (@P))
AND
(NEXT (SELECT (closingPrice) GREATER THAN (10) FROM (@P))).
THE COUNT OF ((
MY PATTERN IN (
(SELECT closingPrice FROM stocks)
WHERE (stockSymbol) = ("MSFT")))
WHERE (*) = (true)).
Linear
Temporal
Logic!
19. import ca.uqac.lif.cep.*;
public class MyProcessor extends SingleProcessor {
public Queue<Vector<Object>> compute(Vector<Object> inputs)
{
}
public void build(Stack<Object> s)
{
}
}
. . . Create output events from input . . .
. . . Instantiate processor from parse stack . . .
<processor> := . . .
<number> := . . .
<string> := . . .
Add new rules to any symbol from
the basic grammar
20. <processor> := <my_processor> ;
<my_processor> := INCREMENT ( <processor> ) BY <number> ;
Symbols already defined in basic grammar
Adds a new case to an existing rule
21. import ca.uqac.lif.cep.*;
public class MyProcessor extends SingleProcessor {
private int increment;
public Queue<Vector<Object>> compute(Vector<Object> inputs)
{
Queue<Vector<Object>> out = new Queue<Vector<Object>>();
Vector<Object> v = new Vector<Object>();
Integer i = (Integer) inputs.firstElement() + increment;
v.addElement(i);
out.put(v);
return out;
}
. . .
22. . . .
public void build(Stack<Object> s)
{
Number n = (Number) s.pop();
s.pop();
s.pop();
Processor p = (Processor) s.pop();
s.pop();
s.pop();
increment = n.intValue();
Connector.connect(p, this);
s.push(this);
}
}
Read contents of
parse stack
<number>
BY
(
<processor>
)
INCREMENT
Set processor's state
Pipe it to its input
Put on parse stack
23. Some pre-packaged grammar extensions:
Manipulation of name-value tuples
Set theory
Formatted input (CSV, XML, JSON)
Graphing (histograms, scatterplots, ...)
Basic signal processing (smoothing,
peak detection, ...)
Create your own!
25. import ca.uqac.lif.cep.*;
import ca.uqac.lif.cep.eml.tuples.*;
public class MyExample {
public static void main(String[] args)
{
Interpreter my_int = new Interpreter();
my_int.extendGrammar(TupleGrammar.class);
Pullable p = my_int.executeQuery(
""HELLO WORLD"");
for (int i = 0; i < 10; i++)
{
EmlString s = (EmlString) p.pull();
System.out.println(s);
}
}
}
Create query interpreter
Load a grammar extension
Execute a query
Pull an output event