Skip to content
About
Main content

Complex event processing

What is the state of a pattern match, and what keeps it bounded?

CEP matches patterns over a sequence of events. Example, from the fraud team: "an order, then zero or more cancellations, then a refund, all within 30 minutes."

An automaton over event time

A pattern compiles to an (non-deterministic finite automaton): a small state machine that can be in several states at the same time, because a new event may continue several partial matches. The state kept per key is not the events but the set of live partial matches. That is where the cost hides.

With quantifiers (A B* C, meaning "A, then any number of B, then C") and a within bound, the number of simultaneously live partial matches can be combinatorial in the number of candidate events. So state is O(keys × partial matches), rather than O(keys).

Small example. Pattern A B* C with relaxed matching (other events may occur between matched ones). After one A and k B events, each B can be included in a partial match or not, so there can be 2^k different partial matches. With k = 20 candidate B events that is 2^20 = 1,048,576 partial matches for one key.

candidate B events seen after an A
Data table
Live partial matches for one key, by candidate events
Candidate B events kPartial matches
01
0.3751.3
0.751.68
1.132.18
1.52.83
1.883.67
2.254.76
2.636.17
38
3.3810.4
3.7513.5
4.1317.4
4.522.6
4.8829.3
5.2538.1
5.6349.4
664
6.3883
6.75108
7.13140
7.5181
7.88235
8.25304
8.63395
9512
9.38664
9.75861
10.11.12K
10.51.45K
10.91.88K
11.32.44K
11.63.16K
124.1K
12.45.31K
12.86.89K
13.18.93K
13.511.6K
13.915K
14.319.5K
14.625.3K
1532.8K
15.442.5K
15.855.1K
16.171.5K
16.592.7K
16.9120K
17.3156K
17.6202K
18262K
18.4340K
18.8441K
19.1572K
19.5741K
19.9962K
20.31.25M
20.61.62M
212.1M
21.42.72M
21.83.53M
22.14.57M
22.55.93M
22.97.69M
23.39.98M
23.612.9M
2416.8M
24.421.8M
24.828.2M
25.136.6M
25.547.5M
25.961.5M
26.379.8M
26.6103M
27134M
27.4174M
27.8226M
28.1293M
28.5380M
28.9492M
29.3638M
29.6828M
301.07B

Bounding mechanisms are all about pruning

  • The within timeout kills stale partial matches. It is the of .
  • Contiguity semantics decide how many branches are spawned per event. Strict contiguity (matched events must be directly adjacent) spawns few. Relaxed contiguity (other events may lie between) spawns many.
  • The decides how many overlapping matches survive. "Skip past last match" (continue after the last event of a found match) instead of "skip to next row" (restart from the event after the first matched one) can be the difference between linear and quadratic state.

The sort buffer

The NFA assumes per-key input is in event order, which it is not. So a CEP needs an event-time sort buffer in front of it: events wait until the passes them, then are released in timestamp order. This is another retention rule, sized by the allowed lateness (how late an event may be and still be used). It is paid for here.