[
https://issues.apache.org/jira/browse/FLINK-6198?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16034936#comment-16034936
]
ASF GitHub Bot commented on FLINK-6198:
---------------------------------------
Github user alpinegizmo commented on a diff in the pull request:
https://github.com/apache/flink/pull/4041#discussion_r119888607
--- Diff: docs/dev/libs/cep.md ---
@@ -246,63 +334,399 @@ pattern.where(event => ... /* some condition
*/).or(event => ... /* or condition
</div>
</div>
-Next, we can append further states to detect complex patterns.
-We can control the contiguity of two succeeding events to be accepted by
the pattern.
+##### Conditions on Contiguity
-Strict contiguity means that two matching events have to be directly the
one after the other.
-This means that no other events can occur in between.
-A strict contiguity pattern state can be created via the `next` method.
+FlinkCEP supports the following forms of contiguity between events:
+
+ 1. Strict Contiguity: which expects all matching events to appear
strictly the one after the other,
+ without any non-matching events in-between.
+
+ 2. Relaxed Contiguity: which simply ignores non-matching events appearing
in-between the matching ones.
+
+ 3. Non-Deterministic Relaxed Contiguity: which further relaxes contiguity
by also creating alternative
+ matches which ignore also matching events.
+
+To illustrate the above with an example, a pattern sequence `a+ b` (one or
more `a`s followed by a `b`) with
+input `a1, c, a2, b` will have the following results:
+
+ 1. Strict Contiguity: `a2 b` because there is `c` `a1` and `a2` so `a1`
is discarded.
+
+ 2. Relaxed Contiguity: `a1 b` and `a1 a2 b`, as `c` will get simply
ignored.
+
+ 3. Non-Deterministic Relaxed Contiguity: `a1 b`, `a2 b` and `a1 a2 b`.
+
+For looping states (e.g. `oneOrMore()` and `times()`) the default is
*relaxed contiguity*. If you want
+strict contiguity, you have to explicitly specify it by using the
`consecutive()` call, and if you want
+*non-deterministic relaxed contiguity* you can use the
`allowCombinations()` call.
<div class="codetabs" markdown="1">
<div data-lang="java" markdown="1">
+<table class="table table-bordered">
+ <thead>
+ <tr>
+ <th class="text-left" style="width: 25%">Pattern Operation</th>
+ <th class="text-center">Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><strong>where(condition)</strong></td>
+ <td>
+ <p>Defines a condition for the current state. Only if an
event satisifes the condition,
+ it can match the state. Multiple consecutive where()
clauses lead to their condtions being
+ ANDed:</p>
+{% highlight java %}
+patternState.where(new IterativeCondition<Event>() {
+ @Override
+ public boolean filter(Event value, Context ctx) throws Exception {
+ return ... // some condition
+ }
+});
+{% endhighlight %}
+ </td>
+ </tr>
+ <tr>
+ <td><strong>or(condition)</strong></td>
+ <td>
+ <p>Adds a new condition which is ORed with an existing
one. Only if an event passes one of the
+ conditions, it can match the state:</p>
+{% highlight java %}
+patternState.where(new IterativeCondition<Event>() {
+ @Override
+ public boolean filter(Event value, Context ctx) throws Exception {
+ return ... // some condition
+ }
+}).or(new IterativeCondition<Event>() {
+ @Override
+ public boolean filter(Event value, Context ctx) throws Exception {
+ return ... // alternative condition
+ }
+});
+{% endhighlight %}
+ </td>
+ </tr>
+ <tr>
+ <td><strong>subtype(subClass)</strong></td>
+ <td>
+ <p>Defines a subtype condition for the current pattern
state. Only if an event is of this subtype,
+ it can match the state:</p>
{% highlight java %}
-Pattern<Event, ?> strictNext = start.next("middle");
+patternState.subtype(SubEvent.class);
{% endhighlight %}
+ </td>
+ </tr>
+ <tr>
+ <td><strong>oneOrMore()</strong></td>
+ <td>
+ <p>Specifies that this state expects at least one occurrence
of a matching event.</p>
+ <p>By default a relaxed internal contiguity (between
subsequent events) is used. For more info on the
+ internal contiguity see <a
href="#consecutive_java">consecutive</a></p>
+ {% highlight java %}
+ patternState.oneOrMore();
+ {% endhighlight %}
+ </td>
+ </tr>
+ <tr>
+ <td><strong>times(#ofTimes)</strong></td>
+ <td>
+ <p>Specifies that this state expects an exact number of
occurrences of a matching event.</p>
+ <p>By default a relaxed internal contiguity (between
subsequent events) is used. For more info on the
+ internal contiguity see <a
href="#consecutive_java">consecutive</a></p>
+{% highlight java %}
+patternState.times(2);
+{% endhighlight %}
+ </td>
+ </tr>
+ <tr>
+ <td><strong>optional()</strong></td>
+ <td>
+ <p>Specifies that this pattern is optional, i.e. it may not
occur at all. This is applicable to all
+ aforementioned quantifiers.</p>
+ {% highlight java %}
+ patternState.oneOrMore().optional();
+ {% endhighlight %}
+ </td>
+ </tr>
+ <tr>
+ <td><strong>consecutive()</strong><a
name="consecutive_java"></a></td>
+ <td>
+ <p>Works in conjunction with oneOrMore() and times() and
imposes strict contiguity between the matching
+ events, i.e. any non-matching element breaks the match (as
in next()).</p>
+ <p>If not applied a relaxed contiguity (as in followedBy())
is used.</p>
+
+ <p>E.g. a pattern like:</p>
+ {% highlight java %}
+ Pattern.<Event>begin("start").where(new
SimpleCondition<Event>() {
+ @Override
+ public boolean filter(Event value) throws Exception {
+ return value.getName().equals("c");
+ }
+ })
+ .followedBy("middle").where(new SimpleCondition<Event>() {
+ @Override
+ public boolean filter(Event value) throws Exception {
+ return value.getName().equals("a");
+ }
+ }).oneOrMore().consecutive()
+ .followedBy("end1").where(new SimpleCondition<Event>() {
+ @Override
+ public boolean filter(Event value) throws Exception {
+ return value.getName().equals("b");
+ }
+ });
+ {% endhighlight %}
+ <p>Will generate the following matches for an input
sequence: C D A1 A2 A3 D A4 B</p>
+
+ <p>with consecutive applied: {C A1 B}, {C A1 A2 B}, {C A1 A2
A3 B}</p>
+ <p>without consecutive applied: {C A1 B}, {C A1 A2 B}, {C A1
A2 A3 B}, {C A1 A2 A3 A4 B}</p>
+ </td>
+ </tr>
+ <tr>
+ <td><strong>allowCombinations()</strong><a
name="allow_comb_java"></a></td>
+ <td>
+ <p>Works in conjunction with oneOrMore() and times() and
imposes non-deterministic relaxed contiguity
+ between the matching events (as in followedByAny()).</p>
+ <p>If not applied a relaxed contiguity (as in followedBy) is
used.</p>
+
+ <p>E.g. a pattern like:</p>
+ {% highlight java %}
+ Pattern.<Event>begin("start").where(new
SimpleCondition<Event>() {
+ @Override
+ public boolean filter(Event value) throws Exception {
+ return value.getName().equals("c");
+ }
+ })
+ .followedBy("middle").where(new SimpleCondition<Event>() {
+ @Override
+ public boolean filter(Event value) throws Exception {
+ return value.getName().equals("a");
+ }
+ }).oneOrMore().allowCombinations()
+ .followedBy("end1").where(new SimpleCondition<Event>() {
+ @Override
+ public boolean filter(Event value) throws Exception {
+ return value.getName().equals("b");
+ }
+ });
+ {% endhighlight %}
+ <p>Will generate the following matches for an input
sequence: C D A1 A2 A3 D A4 B</p>
+
+ <p>with combinations enabled: {C A1 B}, {C A1 A2 B}, {C A1
A3 B}, {C A1 A4 B}, {C A1 A2 A3 B}, {C A1 A2 A4 B}, {C A1 A3 A4 B}, {C A1 A2 A3
A4 B}</p>
+ <p>without combinations enabled: {C A1 B}, {C A1 A2 B}, {C
A1 A2 A3 B}, {C A1 A2 A3 A4 B}</p>
+ </td>
+ </tr>
+ </tbody>
+</table>
</div>
<div data-lang="scala" markdown="1">
+<table class="table table-bordered">
+ <thead>
+ <tr>
+ <th class="text-left" style="width: 25%">Pattern Operation</th>
+ <th class="text-center">Description</th>
+ </tr>
+ </thead>
+ <tbody>
+
+ <tr>
+ <td><strong>where(condition)</strong></td>
+ <td>
+ <p>Defines a condition for the current state. Only if an
event satisifes the condition,
+ it can match the state. Multiple consecutive where() clauses
lead to their condtions being
+ ANDed:</p>
{% highlight scala %}
-val strictNext: Pattern[Event, _] = start.next("middle")
+patternState.where(event => ... /* some condition */)
{% endhighlight %}
+ </td>
+ </tr>
+ <tr>
+ <td><strong>or(condition)</strong></td>
+ <td>
+ <p>Adds a new condition which is ORed with an existing
one. Only if an event passes one of the
+ conditions, it can match the state:</p>
+{% highlight scala %}
+patternState.where(event => ... /* some condition */)
+ .or(event => ... /* alternative condition */)
+{% endhighlight %}
+ </td>
+ </tr>
+ <tr>
+ <td><strong>subtype(subClass)</strong></td>
+ <td>
+ <p>Defines a subtype condition for the current pattern
state. Only if an event is of this subtype,
+ it can match the state:</p>
+{% highlight scala %}
+patternState.subtype(classOf[SubEvent])
+{% endhighlight %}
+ </td>
+ </tr>
+ <tr>
+ <td><strong>oneOrMore()</strong></td>
+ <td>
+ <p>Specifies that this state expects at least one
occurrence of a matching event.</p>
+ <p>By default a relaxed internal contiguity
(between subsequent events) is used. For more info on the
+ internal contiguity see <a
href="#consecutive_scala">consecutive</a></p>
+ {% highlight scala %}
+ patternState.oneOrMore()
+ {% endhighlight %}
+ </td>
+ </tr>
+ <tr>
+ <td><strong>times(#ofTimes)</strong></td>
+ <td>
+ <p>Specifies that this state expects an exact number
of occurrences of a matching event.</p>
+ <p>By default a relaxed internal
contiguity (between subsequent events) is used.
+ For more info on the internal
contiguity see <a href="#consecutive_scala">consecutive</a></p>
+ {% highlight scala %}
+ patternState.times(2)
+ {% endhighlight %}
+ </td>
+ </tr>
+ <tr>
+ <td><strong>optional()</strong></td>
+ <td>
+ <p>Specifies that this pattern is optional, i.e. it may not
occur at all. This is applicable to all
+ aforementioned quantifiers.</p>
+ {% highlight scala %}
+ patternState.oneOrMore().optional()
+ {% endhighlight %}
+ </td>
+ </tr>
+ <tr>
+ <td><strong>consecutive()</strong><a
name="consecutive_scala"></a></td>
+ <td>
+ <p>Works in conjunction with oneOrMore() and times() and
imposes strict contiguity between the matching
+ events, i.e. any non-matching element breaks the
match (as in next()).</p>
+ <p>If not applied a relaxed contiguity (as in
followedBy()) is used.</p>
+
+ <p>E.g. a pattern like:</p>
+ {% highlight scala %}
+ Pattern.begin("start").where(_.getName().equals("c"))
+ .followedBy("middle").where(_.getName().equals("a"))
+ .oneOrMore().consecutive()
+ .followedBy("end1").where(_.getName().equals("b"));
+ {% endhighlight %}
+
+ <p>Will generate the following matches for an input sequence:
C D A1 A2 A3 D A4 B</p>
+
+ <p>with consecutive applied: {C A1 B}, {C A1 A2
B}, {C A1 A2 A3 B}</p>
+ <p>without consecutive applied: {C A1 B}, {C A1
A2 B}, {C A1 A2 A3 B}, {C A1 A2 A3 A4 B}</p>
+ </td>
+ </tr>
+ <tr>
+ <td><strong>allowCombinations()</strong><a
name="allow_comb_java"></a></td>
+ <td>
+ <p>Works in conjunction with oneOrMore() and times() and
imposes non-deterministic relaxed contiguity
+ between the matching events (as in
followedByAny()).</p>
+ <p>If not applied a relaxed contiguity (as in
followedBy) is used.</p>
+
+ <p>E.g. a pattern like:</p>
+ {% highlight scala %}
+ Pattern.begin("start").where(_.getName().equals("c"))
+ .followedBy("middle").where(_.getName().equals("a"))
+ .oneOrMore().allowCombinations()
+ .followedBy("end1").where(_.getName().equals("b"));
+ {% endhighlight %}
+
+ <p>Will generate the following matches for an input
sequence: C D A1 A2 A3 D A4 B</p>
+
+ <p>with combinations enabled: {C A1 B}, {C A1 A2 B},
{C A1 A3 B}, {C A1 A4 B}, {C A1 A2 A3 B}, {C A1 A2 A4 B}, {C A1 A3 A4 B}, {C A1
A2 A3 A4 B}</p>
+ <p>without combinations enabled: {C A1 B}, {C A1 A2
B}, {C A1 A2 A3 B}, {C A1 A2 A3 A4 B}</p>
+ </td>
+ </tr>
+ </tbody>
+</table>
</div>
+
</div>
-Non-strict contiguity means that other events are allowed to occur
in-between two matching events.
-A non-strict contiguity pattern state can be created via the `followedBy`
or `followedByAny` method.
+### Combining States
+
+Now that we have seen how an individual state can look, it is time to see
how to combine them into a full pattern sequence.
+
+A pattern sequence has to start with an initial state, as shown below:
<div class="codetabs" markdown="1">
<div data-lang="java" markdown="1">
{% highlight java %}
-Pattern<Event, ?> nonStrictNext = start.followedBy("middle");
+Pattern<Event, ?> start = Pattern.<Event>begin("start");
{% endhighlight %}
</div>
<div data-lang="scala" markdown="1">
{% highlight scala %}
-val nonStrictNext : Pattern[Event, _] = start.followedBy("middle")
+val start : Pattern[Event, _] = Pattern.begin("start")
{% endhighlight %}
</div>
</div>
-For non-strict contiguity one can specify if only the first succeeding
matching event will be matched, or
-all. In the latter case multiple matches will be emitted for the same
beginning.
+Next, you can append more states to your pattern by specifying the desired
*contiguity conditions* between them.
+This can be done using:
+
+1. `next()`, for *strict*,
+2. `followedBy()`, for *relaxed*, and
+3. `followedByAny()`, for *non-deterministic relaxed* contiguity.
+
+or
+
+1. `notNext()`, if you do not want an event type to directly follow another
+2. `notFollowedBy()`, if you do not want an event type to be anywhere
between two other event types
+
+
+<span class="label label-danger">Attention</span> A pattern sequence
cannot end in `notFollowedBy()`.
+
+<span class="label label-danger">Attention</span> A `NOT` state cannot be
preceded by an optional one.
<div class="codetabs" markdown="1">
<div data-lang="java" markdown="1">
{% highlight java %}
-Pattern<Event, ?> nonStrictNext = start.followedByAny("middle");
+
+// strict contiguity
+Pattern<Event, ?> strict = start.next("middle").where(...);
+
+// relaxed contiguity
+Pattern<Event, ?> relaxed = start.followedBy("middle").where(...);
+
+// non-deterministic relaxed contiguity
+Pattern<Event, ?> nonDetermin = start.followedByAny("middle").where(...);
+
+// NOT pattern with strict contiguity
+Pattern<Event, ?> strictNot = start.notNext("not").where(...);
+
+// NOT pattern with relaxed contiguity
+Pattern<Event, ?> relaxedNot = start.notFollowedBy("not").where(...);
+
{% endhighlight %}
</div>
<div data-lang="scala" markdown="1">
{% highlight scala %}
-val nonStrictNext : Pattern[Event, _] = start.followedByAny("middle")
+
+// strict contiguity
+val strict: Pattern[Event, _] = start.next("middle").where(...)
+
+// relaxed contiguity
+val relaxed: Pattern[Event, _] = start.followedBy("middle").where(...)
+
+// non-deterministic relaxed contiguity
+val nonDetermin: Pattern[Event, _] =
start.followedByAny("middle").where(...)
+
+// NOT pattern with strict contiguity
+val strictNot: Pattern[Event, _] = start.notNext("not").where(...)
+
+// NOT pattern with relaxed contiguity
+val relaxedNot: Pattern[Event, _] = start.notFollowedBy("not").where(...)
+
{% endhighlight %}
</div>
-
</div>
-It is also possible to define a temporal constraint for the pattern to be
valid.
-For example, one can define that a pattern should occur within 10 seconds
via the `within` method.
+
+Bear in mind that relaxed contiguity means that only the first succeeding
matching event will be matched, while
+non-deterministic relaxed contiguity, multiple matches will be emitted for
the same beginning.
--- End diff --
... will be matched, while with non-deterministic ...
> Update the documentation of the CEP library to include all the new features.
> ----------------------------------------------------------------------------
>
> Key: FLINK-6198
> URL: https://issues.apache.org/jira/browse/FLINK-6198
> Project: Flink
> Issue Type: Sub-task
> Components: CEP
> Affects Versions: 1.3.0
> Reporter: Kostas Kloudas
> Assignee: Kostas Kloudas
> Priority: Critical
> Fix For: 1.3.0
>
>
> New features to include:
> * Iterative Functions
> * Quantifiers
> * Time handling
> * Migration from FilterFunction to IterativeCondition
--
This message was sent by Atlassian JIRA
(v6.3.15#6346)