Dynamic Flink CEP: JSON Rule Format
This page defines the JSON format for expressing Complex Event Processing (CEP) rules used by Dynamic Flink CEP. Use it to author, store, and update CEP patterns without changing Java code.
Audience
- Risk control platform developers who integrate or encapsulate CEP rules.
- Risk strategy authors who understand CEP concepts but prefer to write rules in JSON rather than Java.
Overview
A CEP pattern is modeled as a graph:
- A node describes a pattern that matches specific events.
- An edge describes the event selection strategy that moves from one node to the next.
- Graphs can be nested, so a graph may act as a node in a larger graph.
The sections below specify the JSON objects used to describe nodes, quantifiers, conditions, edges, and composite graphs.
Node
A Node represents a complete pattern.
Field | Description | Type | Required | Notes |
---|---|---|---|---|
name | Pattern name | STRING | Yes | Must be unique within the graph. |
type | Node type | ENUM(STRING) | Yes | ATOMIC (no children) or COMPOSITE (has children). |
quantifier | Pattern matching behaviour | OBJECT | Yes | See Quantifier section. |
condition | Filter for events | OBJECT | No | See Condition section. |
Quantifier
A Quantifier defines how frequently and in what manner a pattern should match.
Field | Description | Type | Required | Notes |
---|---|---|---|---|
consumingStrategy | Event selection | ENUM(STRING) | Yes | STRICT , SKIP_TILL_NEXT , SKIP_TILL_ANY . See the Contiguity section. |
times | Bounded repetition | OBJECT | No | See Times object. |
properties | Additional matching properties | ARRAY<ENUM(STRING)> | Yes | See Quantifier properties. |
untilCondition | Early stop for looping patterns | OBJECT | No | Allowed only with LOOPING . See the Condition section. |
Times object
A Times object specifies lower/upper bounds and an optional inner window.
"times": {
"from": 3,
"to": 3,
"windowTime": {
"unit": "MINUTES",
"size": 12
}
}
-
from
,to
:INTEGER
values. -
windowTime
: may benull
, or an object with:unit
:DAYS
|HOURS
|MINUTES
|SECONDS
|MILLISECONDS
size
: numeric (INTEGER
orLONG
).
Note: When no inner window is required, set
"windowTime": null
.
Condition
A Condition filters events for a node.
Field | Description | Type | Required | Notes |
---|---|---|---|---|
type | Condition type | ENUM(STRING) | Yes | CLASS |
... | Custom, serializable fields | varies | No | Allowed for extensibility. |
CLASS
condition
Use a custom Java class to evaluate the condition.
Field | Description | Type | Required |
---|---|---|---|
type | Must be CLASS | STRING | Yes |
className | Fully qualified class name | STRING | Yes |
Example
{
"type": "CLASS",
"className": "ververica.cep.demo.StartCondition"
}
CLASS
with custom parameters
Use when you need to update parameters dynamically without recompiling code.
Field | Description | Type | Required |
---|---|---|---|
type | Must be CLASS | STRING | Yes |
className | Fully qualified class name | STRING | Yes |
args | Custom parameters | ARRAY<STRING> | Yes |
Example
{
"type": "CLASS",
"className": "ververica.cep.demo.CustomMiddleCondition",
"args": ["A", "B", "C"]
}
AVIATOR
condition
Evaluate an Aviator expression that you can update at runtime.
Field | Description | Type | Required |
---|---|---|---|
type | Must be AVIATOR | STRING | Yes |
expression | Expression string | STRING | Yes |
Example
{
"type": "AVIATOR", # Aviator is lightweight scripting language that compiles to the Java bytecode.
"expression": "price > 10"
}
GROOVY
condition
Evaluate a Groovy expression that you can update at runtime.
Field | Description | Type | Required |
---|---|---|---|
type | Must be GROOVY | STRING | Yes |
expression | Expression string | STRING | Yes |
Example
{
"type": "GROOVY", # Groovy is a flexible and an extensible Java-like language that compiles to the Java bytecode.
"expression": "price > 5.0 && name.contains(\"mid\")"
}
Edge
An Edge connects two nodes and defines the event selection strategy between them.
Field | Description | Type | Required |
---|---|---|---|
source | Name of the source pattern | STRING | Yes |
target | Name of the target pattern | STRING | Yes |
type | Contiguity strategy | ENUM(STRING) | Yes |
Valid values for type
: STRICT
, SKIP_TILL_NEXT
, SKIP_TILL_ANY
, NOT_FOLLOW
, NOT_NEXT
. See the Contiguity section.
GraphNode (extends Node)
A GraphNode is a composite pattern sequence. Each item in nodes
is an independent Node; each item in edges
specifies how to transition between them.
Additional fields on top of Node:
Field | Description | Type | Required | Notes |
---|---|---|---|---|
name | Composite pattern name | STRING | Yes | Must be unique. |
type | Must be COMPOSITE | ENUM(STRING) | Yes | |
version | JSON spec version | INTEGER | Yes | Default: 1 . |
nodes | Child patterns | ARRAY<Node> | Yes | Must be non-empty. |
edges | Connections between child patterns | ARRAY<Edge> | Yes | May be empty. |
window | Time window policy | OBJECT | No | See Graph window. |
afterMatchSkipStrategy | Skip strategy after a full match | OBJECT | Yes | See AfterMatchSkipStrategy. |
quantifier | Composite pattern matching behaviour | OBJECT | Yes | See Quantifier. |
Graph window
Two window semantics are supported:
FIRST_AND_LAST
: Maximum time between the start and end of a full composite match.PREVIOUS_AND_CURRENT
: Maximum time between adjacent child pattern matches.
Example
"window": {
"type": "FIRST_AND_LAST",
"time": {
"unit": "DAYS",
"size": 1
}
}
unit
:DAYS
|HOURS
|MINUTES
|SECONDS
|MILLISECONDS
size
: numeric (INTEGER
orLONG
).
AfterMatchSkipStrategy
Controls which partial matches are kept or discarded after a match is emitted.
Field | Description | Type | Required | Notes |
---|---|---|---|---|
type | Strategy type | ENUM(STRING) | Yes | One of the values below. |
patternName | Pattern name used by some strategies | STRING | No | Required by SKIP_TO_FIRST / SKIP_TO_LAST . |
Valid type
values
NO_SKIP
— return every successful match (default).SKIP_TO_NEXT
— discard partial matches that start with the same event.SKIP_PAST_LAST_EVENT
— discard partial matches that start between the beginning and end of the emitted match.SKIP_TO_FIRST
— discard partial matches that start between the beginning of the match and the first occurrence ofpatternName
.SKIP_TO_LAST
— discard partial matches that start between the beginning of the match and the last occurrence ofpatternName
.
Event Selection
Value | Description |
---|---|
STRICT | Strict contiguity. No unmatched events may appear between matched events. |
SKIP_TILL_NEXT | Relaxed contiguity. Ignore unmatched events between matches. |
SKIP_TILL_ANY | Non-deterministic relaxed contiguity. Allows additional matches for the same event. |
NOT_NEXT | The event immediately after a given event must not be a specified event. |
NOT_FOLLOW | A specified event must not appear later in the sequence. |
Quantifier properties
Value | Description |
---|---|
SINGLE | The pattern occurs exactly once. |
LOOPING | The pattern may occur multiple times (similar to * or + in regex). |
TIMES | The pattern must occur a specified number of times. |
GREEDY | Prefer the maximum number of matches. |
OPTIONAL | The pattern is optional. |
Examples
Example 1 — Common pattern
Goal (10‑minute window during a promotion):
- User obtains venue coupons (StartCondition) once — optional.
- User adds items to cart (MiddleCondition) at least 3 times.
- User does not complete payment (EndCondition).
Equivalent Java
Pattern<Event, Event> pattern =
Pattern.<Event>begin("start")
.where(new StartCondition())
.optional()
.followedBy("middle")
.where(new MiddleCondition())
.timesOrMore(3)
.notFollowedBy("end")
.where(new EndCondition())
.within(Time.minutes(10));
JSON
{
"name": "end",
"quantifier": {
"consumingStrategy": "SKIP_TILL_NEXT",
"properties": ["SINGLE"],
"times": null,
"untilCondition": null
},
"condition": null,
"nodes": [
{
"name": "end",
"quantifier": {
"consumingStrategy": "SKIP_TILL_NEXT",
"properties": ["SINGLE"],
"times": null,
"untilCondition": null
},
"condition": {
"className": "ververica.cep.demo.condition.EndCondition",
"type": "CLASS"
},
"type": "ATOMIC"
},
{
"name": "middle",
"quantifier": {
"consumingStrategy": "SKIP_TILL_NEXT",
"properties": ["LOOPING"],
"times": {"from": 3, "to": 3, "windowTime": null},
"untilCondition": null
},
"condition": {
"className": "ververica.cep.demo.condition.MiddleCondition",
"type": "CLASS"
},
"type": "ATOMIC"
},
{
"name": "start",
"quantifier": {
"consumingStrategy": "SKIP_TILL_NEXT",
"properties": ["SINGLE", "OPTIONAL"],
"times": null,
"untilCondition": null
},
"condition": {
"className": "ververica.cep.demo.condition.StartCondition",
"type": "CLASS"
},
"type": "ATOMIC"
}
],
"edges": [
{"source": "middle", "target": "end", "type": "NOT_FOLLOW"},
{"source": "start", "target": "middle", "type": "SKIP_TILL_NEXT"}
],
"window": {
"type": "FIRST_AND_LAST",
"time": {"unit": "MINUTES", "size": 10}
},
"afterMatchSkipStrategy": {"type": "NO_SKIP", "patternName": null},
"type": "COMPOSITE",
"version": 1
}
Example 2 — Condition with custom parameters
You can tailor marketing actions to customer classes without recompiling. Define a class-based condition and adjust its args
list at runtime.
Initial condition
{
"type": "CLASS",
"className": "org.apache.flink.cep.pattern.conditions.CustomMiddleCondition",
"args": ["A", "B"]
}
Updated condition
{
"type": "CLASS",
"className": "org.apache.flink.cep.pattern.conditions.CustomMiddleCondition",
"args": ["A", "B", "C"]
}
Notes
- Aviator and Groovy are third‑party technologies.
- Use
LOOPING
withuntilCondition
to stop repetitions early when needed. - Prefer
afterMatchSkipStrategy
over post‑processing filters to control overlap and throughput explicitly.