Uploaded image for project: 'Flink'
  1. Flink
  2. FLINK-6674 Update release 1.3 docs
  3. FLINK-6198

Update the documentation of the CEP library to include all the new features.

    Details

    • Type: Sub-task
    • Status: Closed
    • Priority: Critical
    • Resolution: Fixed
    • Affects Version/s: 1.3.0
    • Fix Version/s: 1.3.0
    • Component/s: CEP
    • Labels:
      None

      Description

      New features to include:

      • Iterative Functions
      • Quantifiers
      • Time handling
      • Migration from FilterFunction to IterativeCondition

        Issue Links

          Activity

          Hide
          NicoK Nico Kruber added a comment -

          Please also extend the migration guide at docs/dev/migration.md with some notes about the API changes.

          Show
          NicoK Nico Kruber added a comment - Please also extend the migration guide at docs/dev/migration.md with some notes about the API changes.
          Hide
          githubbot ASF GitHub Bot added a comment -

          GitHub user kl0u opened a pull request:

          https://github.com/apache/flink/pull/4041

          FLINK-6198 [cep] Update CEP documentation.

          R @tzulitai @dawidwys

          You can merge this pull request into a Git repository by running:

          $ git pull https://github.com/kl0u/flink cep-doc

          Alternatively you can review and apply these changes as the patch at:

          https://github.com/apache/flink/pull/4041.patch

          To close this pull request, make a commit to your master/trunk branch
          with (at least) the following in the commit message:

          This closes #4041


          commit 2ce49dc722b72a31a178ee6a0763919597646ea6
          Author: kkloudas <kkloudas@gmail.com>
          Date: 2017-05-23T17:07:42Z

          FLINK-6198 [cep] Update CEP documentation.


          Show
          githubbot ASF GitHub Bot added a comment - GitHub user kl0u opened a pull request: https://github.com/apache/flink/pull/4041 FLINK-6198 [cep] Update CEP documentation. R @tzulitai @dawidwys You can merge this pull request into a Git repository by running: $ git pull https://github.com/kl0u/flink cep-doc Alternatively you can review and apply these changes as the patch at: https://github.com/apache/flink/pull/4041.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #4041 commit 2ce49dc722b72a31a178ee6a0763919597646ea6 Author: kkloudas <kkloudas@gmail.com> Date: 2017-05-23T17:07:42Z FLINK-6198 [cep] Update CEP documentation.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user dawidwys commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119595945

          — Diff: docs/dev/libs/cep.md —
          @@ -874,3 +1141,19 @@ val alerts = patternStream.select(createAlert(_)))

          {% endhighlight %}

          </div>
          </div>
          +
          +## Migrating from an older Flink version
          +
          +The CEP library in Flink-1.3 ships with a number of new features which have led to some changes in the API. Here we
          +describe the changes that you need to make to your old CEP jobs, in order to be able to run them with Flink-1.3. After
          +making these changes and recompiling your job, you will be able to resume its execution from a savepoint taken with the
          +old version of your job, i.e. without having to re-process your past data.
          +
          +The changes required are:
          +
          +1. Change your conditions (the ones in the `where(...)` clause) to extend the `SimpleCondition` class instead of
          +implementing the `FilterFunction` interface.
          +
          +2. Change your functions provided as arguments to the `select(...)` and `flatSelect(...)` methods to expect a list of
          +events associated with each state (`List` in `Java`, `Iterable` in `Scala`). This is because with the addition of
          +the looping states, multiple input events can much a single (looping) state.
          — End diff –

          much -> match

          Show
          githubbot ASF GitHub Bot added a comment - Github user dawidwys commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119595945 — Diff: docs/dev/libs/cep.md — @@ -874,3 +1141,19 @@ val alerts = patternStream.select(createAlert(_))) {% endhighlight %} </div> </div> + +## Migrating from an older Flink version + +The CEP library in Flink-1.3 ships with a number of new features which have led to some changes in the API. Here we +describe the changes that you need to make to your old CEP jobs, in order to be able to run them with Flink-1.3. After +making these changes and recompiling your job, you will be able to resume its execution from a savepoint taken with the +old version of your job, i.e. without having to re-process your past data. + +The changes required are: + +1. Change your conditions (the ones in the `where(...)` clause) to extend the `SimpleCondition` class instead of +implementing the `FilterFunction` interface. + +2. Change your functions provided as arguments to the `select(...)` and `flatSelect(...)` methods to expect a list of +events associated with each state (`List` in `Java`, `Iterable` in `Scala`). This is because with the addition of +the looping states, multiple input events can much a single (looping) state. — End diff – much -> match
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user kl0u commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119596846

          — Diff: docs/dev/libs/cep.md —
          @@ -874,3 +1141,19 @@ val alerts = patternStream.select(createAlert(_)))

          {% endhighlight %}

          </div>
          </div>
          +
          +## Migrating from an older Flink version
          +
          +The CEP library in Flink-1.3 ships with a number of new features which have led to some changes in the API. Here we
          +describe the changes that you need to make to your old CEP jobs, in order to be able to run them with Flink-1.3. After
          +making these changes and recompiling your job, you will be able to resume its execution from a savepoint taken with the
          +old version of your job, i.e. without having to re-process your past data.
          +
          +The changes required are:
          +
          +1. Change your conditions (the ones in the `where(...)` clause) to extend the `SimpleCondition` class instead of
          +implementing the `FilterFunction` interface.
          +
          +2. Change your functions provided as arguments to the `select(...)` and `flatSelect(...)` methods to expect a list of
          +events associated with each state (`List` in `Java`, `Iterable` in `Scala`). This is because with the addition of
          +the looping states, multiple input events can much a single (looping) state.
          — End diff –

          hehe good "cats" (catch)

          Show
          githubbot ASF GitHub Bot added a comment - Github user kl0u commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119596846 — Diff: docs/dev/libs/cep.md — @@ -874,3 +1141,19 @@ val alerts = patternStream.select(createAlert(_))) {% endhighlight %} </div> </div> + +## Migrating from an older Flink version + +The CEP library in Flink-1.3 ships with a number of new features which have led to some changes in the API. Here we +describe the changes that you need to make to your old CEP jobs, in order to be able to run them with Flink-1.3. After +making these changes and recompiling your job, you will be able to resume its execution from a savepoint taken with the +old version of your job, i.e. without having to re-process your past data. + +The changes required are: + +1. Change your conditions (the ones in the `where(...)` clause) to extend the `SimpleCondition` class instead of +implementing the `FilterFunction` interface. + +2. Change your functions provided as arguments to the `select(...)` and `flatSelect(...)` methods to expect a list of +events associated with each state (`List` in `Java`, `Iterable` in `Scala`). This is because with the addition of +the looping states, multiple input events can much a single (looping) state. — End diff – hehe good "cats" (catch)
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user tzulitai commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119607288

          — Diff: docs/dev/libs/cep.md —
          @@ -246,63 +333,118 @@ 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 consecutive events:

          -<div class="codetabs" markdown="1">
          -<div data-lang="java" markdown="1">
          -

          {% highlight java %}
          -Pattern<Event, ?> strictNext = start.next("middle");
          -{% endhighlight %}
          -</div>
          + 1. Strict Contiguity: which expects all matching events to appear strictly the one after the other,
          + without any non-matching events in-between.

          -<div data-lang="scala" markdown="1">
          -{% highlight scala %}
          -val strictNext: Pattern[Event, _] = start.next("middle")
          -{% endhighlight %}
          -</div>
          -</div>
          + 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.

          -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.
          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`.
          +
          +Contiguity conditions should be specified both within individual (looping) states but also
          +across states. 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.
          +
          +### 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.
          +
          +Finally, it is also possible to define a temporal constraint for the pattern to be valid.
          +For example, you can define that a pattern should occur within 10 seconds via the `pattern.within()` method.
          Temporal patterns are supported for both [processing and event time](site.baseurl/dev/event_time.html).

          <div class="codetabs" markdown="1">
          — End diff –

          I wonder if it makes sense to break up this table into 2 parts, one placed under the "Individual States" section, and "Combining States" section, to make it clearer which API calls are for describing the construction of an individual state and which ones are for combining different states.

          Show
          githubbot ASF GitHub Bot added a comment - Github user tzulitai commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119607288 — Diff: docs/dev/libs/cep.md — @@ -246,63 +333,118 @@ 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 consecutive events: -<div class="codetabs" markdown="1"> -<div data-lang="java" markdown="1"> - {% highlight java %} -Pattern<Event, ?> strictNext = start.next("middle"); -{% endhighlight %} -</div> + 1. Strict Contiguity: which expects all matching events to appear strictly the one after the other, + without any non-matching events in-between. -<div data-lang="scala" markdown="1"> -{% highlight scala %} -val strictNext: Pattern [Event, _] = start.next("middle") -{% endhighlight %} -</div> -</div> + 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. -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. 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`. + +Contiguity conditions should be specified both within individual (looping) states but also +across states. 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. + +### 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. + +Finally, it is also possible to define a temporal constraint for the pattern to be valid. +For example, you can define that a pattern should occur within 10 seconds via the `pattern.within()` method. Temporal patterns are supported for both [processing and event time] ( site.baseurl /dev/event_time.html). <div class="codetabs" markdown="1"> — End diff – I wonder if it makes sense to break up this table into 2 parts, one placed under the "Individual States" section, and "Combining States" section, to make it clearer which API calls are for describing the construction of an individual state and which ones are for combining different states.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user tzulitai commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119606025

          — Diff: docs/dev/libs/cep.md —
          @@ -246,63 +333,118 @@ 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 consecutive events:

          -<div class="codetabs" markdown="1">
          -<div data-lang="java" markdown="1">
          -

          {% highlight java %}

          -Pattern<Event, ?> strictNext = start.next("middle");
          -

          {% endhighlight %}
          -</div>
          + 1. Strict Contiguity: which expects all matching events to appear strictly the one after the other,
          + without any non-matching events in-between.

          -<div data-lang="scala" markdown="1">
          -{% highlight scala %}
          -val strictNext: Pattern[Event, _] = start.next("middle")
          -{% endhighlight %}

          -</div>
          -</div>
          + 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.

          -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.
          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`.
          +
          +Contiguity conditions should be specified both within individual (looping) states but also
          +across states. For looping states (e.g. `oneOrMore()` and `times()`) the default is relaxed contiguity. If you want
          — End diff –

          Regarding "Contiguity conditions should be specified both within individual (looping) states but also across states".

          I'm not sure if it makes sense to present the detail that across states require contiguity conditions at this part of the doc. The main reason is that this section is about "Individual States", so the information was a bit "disruptive" when I first stumbled across it.

          Show
          githubbot ASF GitHub Bot added a comment - Github user tzulitai commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119606025 — Diff: docs/dev/libs/cep.md — @@ -246,63 +333,118 @@ 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 consecutive events: -<div class="codetabs" markdown="1"> -<div data-lang="java" markdown="1"> - {% highlight java %} -Pattern<Event, ?> strictNext = start.next("middle"); - {% endhighlight %} -</div> + 1. Strict Contiguity: which expects all matching events to appear strictly the one after the other, + without any non-matching events in-between. -<div data-lang="scala" markdown="1"> -{% highlight scala %} -val strictNext: Pattern [Event, _] = start.next("middle") -{% endhighlight %} -</div> -</div> + 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. -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. 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`. + +Contiguity conditions should be specified both within individual (looping) states but also +across states. For looping states (e.g. `oneOrMore()` and `times()`) the default is relaxed contiguity . If you want — End diff – Regarding "Contiguity conditions should be specified both within individual (looping) states but also across states". I'm not sure if it makes sense to present the detail that across states require contiguity conditions at this part of the doc. The main reason is that this section is about "Individual States", so the information was a bit "disruptive" when I first stumbled across it.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user tzulitai commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119602446

          — Diff: docs/dev/libs/cep.md —
          @@ -65,21 +67,49 @@ Next, you have to add the FlinkCEP dependency to the `pom.xml` of your project.
          Note that FlinkCEP is currently not part of the binary distribution.
          See linking with it for cluster execution [here](site.baseurl/dev/linking.html).

          -Now you can start writing your first CEP program using the pattern API.
          +Now you can start writing your first CEP program using the Pattern API.
          +
          +<span class="label label-danger">Attention</span> The events in the `DataStream` to which
          +you want to apply pattern matching have to implement proper `equals()` and `hashCode()` methods
          +because these are used for comparing and matching events.

          <div class="codetabs" markdown="1">
          <div data-lang="java" markdown="1">

          {% highlight java %}

          DataStream<Event> input = ...

          -Pattern<Event, ?> pattern = Pattern.begin("start").where(evt -> evt.getId() == 42)

          • .next("middle").subtype(SubEvent.class).where(subEvt -> subEvt.getVolume() >= 10.0)
          • .followedBy("end").where(evt -> evt.getName().equals("end"));
            +Pattern<Event, ?> pattern = Pattern.begin("start").where(
            + new SimpleCondition<Event>() {
            + @Override
            + public boolean filter(Event event) {
            + return evt.getId() == 42;
              • End diff –

          `evt` --> `event`

          Show
          githubbot ASF GitHub Bot added a comment - Github user tzulitai commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119602446 — Diff: docs/dev/libs/cep.md — @@ -65,21 +67,49 @@ Next, you have to add the FlinkCEP dependency to the `pom.xml` of your project. Note that FlinkCEP is currently not part of the binary distribution. See linking with it for cluster execution [here] ( site.baseurl /dev/linking.html). -Now you can start writing your first CEP program using the pattern API. +Now you can start writing your first CEP program using the Pattern API. + +<span class="label label-danger">Attention</span> The events in the `DataStream` to which +you want to apply pattern matching have to implement proper `equals()` and `hashCode()` methods +because these are used for comparing and matching events. <div class="codetabs" markdown="1"> <div data-lang="java" markdown="1"> {% highlight java %} DataStream<Event> input = ... -Pattern<Event, ?> pattern = Pattern.begin("start").where(evt -> evt.getId() == 42) .next("middle").subtype(SubEvent.class).where(subEvt -> subEvt.getVolume() >= 10.0) .followedBy("end").where(evt -> evt.getName().equals("end")); +Pattern<Event, ?> pattern = Pattern.begin("start").where( + new SimpleCondition<Event>() { + @Override + public boolean filter(Event event) { + return evt.getId() == 42; End diff – `evt` --> `event`
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user tzulitai commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119602408

          — Diff: docs/dev/libs/cep.md —
          @@ -65,21 +67,49 @@ Next, you have to add the FlinkCEP dependency to the `pom.xml` of your project.
          Note that FlinkCEP is currently not part of the binary distribution.
          See linking with it for cluster execution [here](site.baseurl/dev/linking.html).

          -Now you can start writing your first CEP program using the pattern API.
          +Now you can start writing your first CEP program using the Pattern API.
          +
          +<span class="label label-danger">Attention</span> The events in the `DataStream` to which
          +you want to apply pattern matching have to implement proper `equals()` and `hashCode()` methods
          +because these are used for comparing and matching events.

          <div class="codetabs" markdown="1">
          <div data-lang="java" markdown="1">

          {% highlight java %}

          DataStream<Event> input = ...

          -Pattern<Event, ?> pattern = Pattern.begin("start").where(evt -> evt.getId() == 42)

          • .next("middle").subtype(SubEvent.class).where(subEvt -> subEvt.getVolume() >= 10.0)
          • .followedBy("end").where(evt -> evt.getName().equals("end"));
            +Pattern<Event, ?> pattern = Pattern.begin("start").where(
              • End diff –

          I think Pattern."<Event>" is required?

          Show
          githubbot ASF GitHub Bot added a comment - Github user tzulitai commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119602408 — Diff: docs/dev/libs/cep.md — @@ -65,21 +67,49 @@ Next, you have to add the FlinkCEP dependency to the `pom.xml` of your project. Note that FlinkCEP is currently not part of the binary distribution. See linking with it for cluster execution [here] ( site.baseurl /dev/linking.html). -Now you can start writing your first CEP program using the pattern API. +Now you can start writing your first CEP program using the Pattern API. + +<span class="label label-danger">Attention</span> The events in the `DataStream` to which +you want to apply pattern matching have to implement proper `equals()` and `hashCode()` methods +because these are used for comparing and matching events. <div class="codetabs" markdown="1"> <div data-lang="java" markdown="1"> {% highlight java %} DataStream<Event> input = ... -Pattern<Event, ?> pattern = Pattern.begin("start").where(evt -> evt.getId() == 42) .next("middle").subtype(SubEvent.class).where(subEvt -> subEvt.getVolume() >= 10.0) .followedBy("end").where(evt -> evt.getName().equals("end")); +Pattern<Event, ?> pattern = Pattern.begin("start").where( End diff – I think Pattern."<Event>" is required?
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user tzulitai commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119604721

          — Diff: docs/dev/libs/cep.md —
          @@ -98,48 +128,105 @@ val result: DataStream[Alert] = patternStream.select(createAlert(_))
          </div>
          </div>

          -Note that we use Java 8 lambdas in our Java code examples to make them more succinct.
          -

            1. The Pattern API

          -The pattern API allows you to quickly define complex event patterns.
          -
          -Each pattern consists of multiple stages or what we call states.
          -In order to go from one state to the next, the user can specify conditions.
          -These conditions can be the contiguity of events or a filter condition on an event.
          -
          -Each pattern has to start with an initial state:
          +The pattern API allows you to quickly define complex pattern sequences that you want to extract
          +from your input stream.
          +
          +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for
          +individual events with the same properties. These simple patterns are called *states*. A complex pattern
          +can be seen as a graph of such states, where transition from one state to the next happens based on user-specified
          +conditions, e.g. `event.getName().equals("start")`. A match is a sequence of input events which visit all
          +states of the complex pattern graph, through a sequence of valid state transitions.
          +
          +<span class="label label-danger">Attention</span> Each state must have a unique name to identify the matched
          +events later on.
          +
          +<span class="label label-danger">Attention</span> State names *CANNOT* contain the character `:`.
          +
          +In the remainder, we start by describing how to define [States](#states), before describing how you can
          +combine individual states into [Complex Patterns](#combining-states).
          +
          +### Individual States
          +
          +A *State* can be either a singleton state, or a looping one. Singleton states accept a single event,
          while looping ones accept more than one. In pattern matching symbols, in the pattern `a b c? d` (or `a`,
          +followed by one or more `b`'s, optionally followed by a `c`, followed by a `d`), `a`, `c?`, and `d` are
          singleton patterns, while `b` is a looping one (see [Quantifiers](#quantifiers)). In addition, each state
          +can have one or more conditions based on which it accepts events (see [Conditions](#conditions)).
          +
          +#### Quantifiers
          +
          +In FlinkCEP, looping patterns can be specified using the methods: `pattern.oneOrMore()`, for states that expect one or
          more occurrences of a given event (e.g. the `b` mentioned previously), and `pattern.times(#ofTimes)` for states that
          +expect a specific number of occurrences of a given type of event, e.g. 4 `a`'s. All states, looping or not, can be made
          +optional using the `pattern.optional()` method. For a state named `start`, the following are valid quantifiers:
          +
          + <div class="codetabs" markdown="1">
          + <div data-lang="java" markdown="1">
          +

          {% highlight java %}

          + // expecting 4 occurrences
          + start.times(4);
          +
          + // expecting 0 or 4 occurrences
          + start.times(4).optional();
          +
          + // expecting 1 or more occurrences
          + start.oneOrMore();
          +
          + // expecting 0 or more occurrences
          + start.oneOrMore().optional();
          +

          {% endhighlight %}
          + </div>
          +
          + <div data-lang="scala" markdown="1">
          + {% highlight scala %}
          + // expecting 4 occurrences
          + start.times(4)
          +
          + // expecting 0 or 4 occurrences
          + start.times(4).optional()
          +
          + // expecting 1 or more occurrences
          + start.oneOrMore()
          +
          + // expecting 0 or more occurrences
          + start.oneOrMore().optional()
          + {% endhighlight %}

          + </div>
          + </div>
          +
          +#### Conditions
          +
          +At every state, and in order to go from one state to the next, you can specify additional *conditions*.
          +These conditions can be related to:
          +
          + 1. a [property of the incoming event](#conditions-on-properties), e.g. its value should be larger than 5,
          + or larger than the average value of the previously accepted events.
          +
          + 2. the [contiguity of the matching events](#conditions-on-contiguity), e.g. detect pattern `a,b,c` without
          + non-matching events between any matching ones.
          +
          The latter refers to "looping" states, i.e. states that can accept more than one event, e.g. the `b` in `a b+ c`,
          +which searches for one or more `b`'s.
          +
          +##### Conditions on Properties
          — End diff –

          I found this title to be very "hidden" in the content, in that its subsection titles "Iterative Conditions" and "Simple Conditions" where actually more prominent.

          Not really sure if this can be addressed though, just pointing out an observation on the built docs.

          Show
          githubbot ASF GitHub Bot added a comment - Github user tzulitai commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119604721 — Diff: docs/dev/libs/cep.md — @@ -98,48 +128,105 @@ val result: DataStream [Alert] = patternStream.select(createAlert(_)) </div> </div> -Note that we use Java 8 lambdas in our Java code examples to make them more succinct. - The Pattern API -The pattern API allows you to quickly define complex event patterns. - -Each pattern consists of multiple stages or what we call states. -In order to go from one state to the next, the user can specify conditions. -These conditions can be the contiguity of events or a filter condition on an event. - -Each pattern has to start with an initial state: +The pattern API allows you to quickly define complex pattern sequences that you want to extract +from your input stream. + +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for +individual events with the same properties. These simple patterns are called * states *. A complex pattern +can be seen as a graph of such states, where transition from one state to the next happens based on user-specified + conditions , e.g. `event.getName().equals("start")`. A match is a sequence of input events which visit all +states of the complex pattern graph, through a sequence of valid state transitions. + +<span class="label label-danger">Attention</span> Each state must have a unique name to identify the matched +events later on. + +<span class="label label-danger">Attention</span> State names * CANNOT * contain the character `:`. + +In the remainder, we start by describing how to define [States] (#states), before describing how you can +combine individual states into [Complex Patterns] (#combining-states). + +### Individual States + +A * State * can be either a singleton state, or a looping one. Singleton states accept a single event, while looping ones accept more than one. In pattern matching symbols, in the pattern `a b c? d` (or `a`, +followed by one or more `b`'s, optionally followed by a `c`, followed by a `d`), `a`, `c?`, and `d` are singleton patterns, while `b ` is a looping one (see [Quantifiers] (#quantifiers)). In addition, each state +can have one or more conditions based on which it accepts events (see [Conditions] (#conditions)). + +#### Quantifiers + +In FlinkCEP, looping patterns can be specified using the methods: `pattern.oneOrMore()`, for states that expect one or more occurrences of a given event (e.g. the `b ` mentioned previously), and `pattern.times(#ofTimes)` for states that +expect a specific number of occurrences of a given type of event, e.g. 4 `a`'s. All states, looping or not, can be made +optional using the `pattern.optional()` method. For a state named `start`, the following are valid quantifiers: + + <div class="codetabs" markdown="1"> + <div data-lang="java" markdown="1"> + {% highlight java %} + // expecting 4 occurrences + start.times(4); + + // expecting 0 or 4 occurrences + start.times(4).optional(); + + // expecting 1 or more occurrences + start.oneOrMore(); + + // expecting 0 or more occurrences + start.oneOrMore().optional(); + {% endhighlight %} + </div> + + <div data-lang="scala" markdown="1"> + {% highlight scala %} + // expecting 4 occurrences + start.times(4) + + // expecting 0 or 4 occurrences + start.times(4).optional() + + // expecting 1 or more occurrences + start.oneOrMore() + + // expecting 0 or more occurrences + start.oneOrMore().optional() + {% endhighlight %} + </div> + </div> + +#### Conditions + +At every state, and in order to go from one state to the next, you can specify additional * conditions *. +These conditions can be related to: + + 1. a [property of the incoming event] (#conditions-on-properties), e.g. its value should be larger than 5, + or larger than the average value of the previously accepted events. + + 2. the [contiguity of the matching events] (#conditions-on-contiguity), e.g. detect pattern `a,b,c` without + non-matching events between any matching ones. + The latter refers to "looping" states, i.e. states that can accept more than one event, e.g. the `b ` in `a b+ c`, +which searches for one or more `b`'s. + +##### Conditions on Properties — End diff – I found this title to be very "hidden" in the content, in that its subsection titles "Iterative Conditions" and "Simple Conditions" where actually more prominent. Not really sure if this can be addressed though, just pointing out an observation on the built docs.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user tzulitai commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119606506

          — Diff: docs/dev/libs/cep.md —
          @@ -98,48 +128,105 @@ val result: DataStream[Alert] = patternStream.select(createAlert(_))
          </div>
          </div>

          -Note that we use Java 8 lambdas in our Java code examples to make them more succinct.
          -

            1. The Pattern API

          -The pattern API allows you to quickly define complex event patterns.
          -
          -Each pattern consists of multiple stages or what we call states.
          -In order to go from one state to the next, the user can specify conditions.
          -These conditions can be the contiguity of events or a filter condition on an event.
          -
          -Each pattern has to start with an initial state:
          +The pattern API allows you to quickly define complex pattern sequences that you want to extract
          +from your input stream.
          +
          +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for
          +individual events with the same properties. These simple patterns are called *states*. A complex pattern
          +can be seen as a graph of such states, where transition from one state to the next happens based on user-specified
          +conditions, e.g. `event.getName().equals("start")`. A match is a sequence of input events which visit all
          +states of the complex pattern graph, through a sequence of valid state transitions.
          +
          +<span class="label label-danger">Attention</span> Each state must have a unique name to identify the matched
          +events later on.
          +
          +<span class="label label-danger">Attention</span> State names *CANNOT* contain the character `:`.
          +
          +In the remainder, we start by describing how to define [States](#states), before describing how you can
          +combine individual states into [Complex Patterns](#combining-states).
          +
          +### Individual States
          +
          +A *State* can be either a singleton state, or a looping one. Singleton states accept a single event,
          while looping ones accept more than one. In pattern matching symbols, in the pattern `a b c? d` (or `a`,
          +followed by one or more `b`'s, optionally followed by a `c`, followed by a `d`), `a`, `c?`, and `d` are
          singleton patterns, while `b` is a looping one (see [Quantifiers](#quantifiers)). In addition, each state
          +can have one or more conditions based on which it accepts events (see [Conditions](#conditions)).
          — End diff –

          Perhaps somewhere in this paragraph, describe that by default, states are singleton? and to make it a looping one, use quantifiers.

          There is a sentence mentioning for looping state see quantifiers, but we can make the information a bit more explicit.

          Show
          githubbot ASF GitHub Bot added a comment - Github user tzulitai commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119606506 — Diff: docs/dev/libs/cep.md — @@ -98,48 +128,105 @@ val result: DataStream [Alert] = patternStream.select(createAlert(_)) </div> </div> -Note that we use Java 8 lambdas in our Java code examples to make them more succinct. - The Pattern API -The pattern API allows you to quickly define complex event patterns. - -Each pattern consists of multiple stages or what we call states. -In order to go from one state to the next, the user can specify conditions. -These conditions can be the contiguity of events or a filter condition on an event. - -Each pattern has to start with an initial state: +The pattern API allows you to quickly define complex pattern sequences that you want to extract +from your input stream. + +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for +individual events with the same properties. These simple patterns are called * states *. A complex pattern +can be seen as a graph of such states, where transition from one state to the next happens based on user-specified + conditions , e.g. `event.getName().equals("start")`. A match is a sequence of input events which visit all +states of the complex pattern graph, through a sequence of valid state transitions. + +<span class="label label-danger">Attention</span> Each state must have a unique name to identify the matched +events later on. + +<span class="label label-danger">Attention</span> State names * CANNOT * contain the character `:`. + +In the remainder, we start by describing how to define [States] (#states), before describing how you can +combine individual states into [Complex Patterns] (#combining-states). + +### Individual States + +A * State * can be either a singleton state, or a looping one. Singleton states accept a single event, while looping ones accept more than one. In pattern matching symbols, in the pattern `a b c? d` (or `a`, +followed by one or more `b`'s, optionally followed by a `c`, followed by a `d`), `a`, `c?`, and `d` are singleton patterns, while `b ` is a looping one (see [Quantifiers] (#quantifiers)). In addition, each state +can have one or more conditions based on which it accepts events (see [Conditions] (#conditions)). — End diff – Perhaps somewhere in this paragraph, describe that by default, states are singleton? and to make it a looping one, use quantifiers. There is a sentence mentioning for looping state see quantifiers, but we can make the information a bit more explicit.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user tzulitai commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119602073

          — Diff: docs/dev/libs/cep.md —
          @@ -23,22 +23,24 @@ specific language governing permissions and limitations
          under the License.
          -->

          -FlinkCEP is the complex event processing library for Flink.
          -It allows you to easily detect complex event patterns in a stream of endless data.
          -Complex events can then be constructed from matching sequences.
          -This gives you the opportunity to quickly get hold of what's really important in your data.
          +FlinkCEP is the Complex Event Processing (CEP) library implemented on top of Flink.
          +It allows you to easily detect event patterns in an endless stream of events, thus
          +giving you the opportunity to quickly get hold of what's really important in your
          +data.

          -<span class="label label-danger">Attention</span> The events in the `DataStream` to which
          -you want to apply pattern matching have to implement proper `equals()` and `hashCode()` methods
          -because these are used for comparing and matching events.
          +This page described the API calls available in Flink CEP. We start by presenting the [Pattern API](#the-pattern-api),
          — End diff –

          "described" --> "describes"

          Show
          githubbot ASF GitHub Bot added a comment - Github user tzulitai commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119602073 — Diff: docs/dev/libs/cep.md — @@ -23,22 +23,24 @@ specific language governing permissions and limitations under the License. --> -FlinkCEP is the complex event processing library for Flink. -It allows you to easily detect complex event patterns in a stream of endless data. -Complex events can then be constructed from matching sequences. -This gives you the opportunity to quickly get hold of what's really important in your data. +FlinkCEP is the Complex Event Processing (CEP) library implemented on top of Flink. +It allows you to easily detect event patterns in an endless stream of events, thus +giving you the opportunity to quickly get hold of what's really important in your +data. -<span class="label label-danger">Attention</span> The events in the `DataStream` to which -you want to apply pattern matching have to implement proper `equals()` and `hashCode()` methods -because these are used for comparing and matching events. +This page described the API calls available in Flink CEP. We start by presenting the [Pattern API] (#the-pattern-api), — End diff – "described" --> "describes"
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user tzulitai commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119607645

          — Diff: docs/dev/libs/cep.md —
          @@ -659,37 +913,45 @@ val patternStream: PatternStream[Event] = CEP.pattern(input, pattern)
          </div>
          </div>

          +The input stream can be keyed or non-keyed depending on your use-case.
          +
          +<span class="label label-danger">Attention</span> Applying your pattern on a non-keyed stream will result is a job with
          +parallelism equal to 1.
          +

              1. Selecting from Patterns
                +
                Once you have obtained a `PatternStream` you can select from detected event sequences via the `select` or `flatSelect` methods.

          <div class="codetabs" markdown="1">
          <div data-lang="java" markdown="1">
          The `select` method requires a `PatternSelectFunction` implementation.
          A `PatternSelectFunction` has a `select` method which is called for each matching event sequence.
          -It receives a map of string/event pairs of the matched events.
          -The string is defined by the name of the state to which the event has been matched.
          -The `select` method can return exactly one result.
          +It receives a match in the form of `Map<String, List<IN>>` where the key is the name of each state in your pattern
          +sequence and the value is a list of all accepted events for that state (`IN` is the type of your input elements).
          — End diff –

          Perhaps add information about the ordering of the list of matched events?

          Show
          githubbot ASF GitHub Bot added a comment - Github user tzulitai commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119607645 — Diff: docs/dev/libs/cep.md — @@ -659,37 +913,45 @@ val patternStream: PatternStream [Event] = CEP.pattern(input, pattern) </div> </div> +The input stream can be keyed or non-keyed depending on your use-case. + +<span class="label label-danger">Attention</span> Applying your pattern on a non-keyed stream will result is a job with +parallelism equal to 1. + Selecting from Patterns + Once you have obtained a `PatternStream` you can select from detected event sequences via the `select` or `flatSelect` methods. <div class="codetabs" markdown="1"> <div data-lang="java" markdown="1"> The `select` method requires a `PatternSelectFunction` implementation. A `PatternSelectFunction` has a `select` method which is called for each matching event sequence. -It receives a map of string/event pairs of the matched events. -The string is defined by the name of the state to which the event has been matched. -The `select` method can return exactly one result. +It receives a match in the form of `Map<String, List<IN>>` where the key is the name of each state in your pattern +sequence and the value is a list of all accepted events for that state (`IN` is the type of your input elements). — End diff – Perhaps add information about the ordering of the list of matched events?
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user kl0u commented on the issue:

          https://github.com/apache/flink/pull/4041

          Thanks a lot for the thorough review @tzulitai ! I will address your comments and then merge.

          Show
          githubbot ASF GitHub Bot added a comment - Github user kl0u commented on the issue: https://github.com/apache/flink/pull/4041 Thanks a lot for the thorough review @tzulitai ! I will address your comments and then merge.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user dawidwys commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119605089

          — Diff: docs/dev/libs/cep.md —
          @@ -98,48 +128,105 @@ val result: DataStream[Alert] = patternStream.select(createAlert(_))
          </div>
          </div>

          -Note that we use Java 8 lambdas in our Java code examples to make them more succinct.
          -

            1. The Pattern API

          -The pattern API allows you to quickly define complex event patterns.
          -
          -Each pattern consists of multiple stages or what we call states.
          -In order to go from one state to the next, the user can specify conditions.
          -These conditions can be the contiguity of events or a filter condition on an event.
          -
          -Each pattern has to start with an initial state:
          +The pattern API allows you to quickly define complex pattern sequences that you want to extract
          +from your input stream.
          +
          +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for
          +individual events with the same properties. These simple patterns are called *states*. A complex pattern
          +can be seen as a graph of such states, where transition from one state to the next happens based on user-specified
          +conditions, e.g. `event.getName().equals("start")`. A match is a sequence of input events which visit all
          — End diff –

          visit -> visits

          Show
          githubbot ASF GitHub Bot added a comment - Github user dawidwys commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119605089 — Diff: docs/dev/libs/cep.md — @@ -98,48 +128,105 @@ val result: DataStream [Alert] = patternStream.select(createAlert(_)) </div> </div> -Note that we use Java 8 lambdas in our Java code examples to make them more succinct. - The Pattern API -The pattern API allows you to quickly define complex event patterns. - -Each pattern consists of multiple stages or what we call states. -In order to go from one state to the next, the user can specify conditions. -These conditions can be the contiguity of events or a filter condition on an event. - -Each pattern has to start with an initial state: +The pattern API allows you to quickly define complex pattern sequences that you want to extract +from your input stream. + +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for +individual events with the same properties. These simple patterns are called * states *. A complex pattern +can be seen as a graph of such states, where transition from one state to the next happens based on user-specified + conditions , e.g. `event.getName().equals("start")`. A match is a sequence of input events which visit all — End diff – visit -> visits
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user dawidwys commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119604886

          — Diff: docs/dev/libs/cep.md —
          @@ -98,48 +128,105 @@ val result: DataStream[Alert] = patternStream.select(createAlert(_))
          </div>
          </div>

          -Note that we use Java 8 lambdas in our Java code examples to make them more succinct.
          -

            1. The Pattern API

          -The pattern API allows you to quickly define complex event patterns.
          -
          -Each pattern consists of multiple stages or what we call states.
          -In order to go from one state to the next, the user can specify conditions.
          -These conditions can be the contiguity of events or a filter condition on an event.
          -
          -Each pattern has to start with an initial state:
          +The pattern API allows you to quickly define complex pattern sequences that you want to extract
          +from your input stream.
          +
          +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for
          +individual events with the same properties. These simple patterns are called *states*. A complex pattern
          — End diff –

          I am aware of the difficulty of naming a single pattern but I am not sure if naming it state is good idea, as internally we use State for something different.

          Do you think the distinction: pattern <-> pattern sequence is not enough?

          Show
          githubbot ASF GitHub Bot added a comment - Github user dawidwys commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119604886 — Diff: docs/dev/libs/cep.md — @@ -98,48 +128,105 @@ val result: DataStream [Alert] = patternStream.select(createAlert(_)) </div> </div> -Note that we use Java 8 lambdas in our Java code examples to make them more succinct. - The Pattern API -The pattern API allows you to quickly define complex event patterns. - -Each pattern consists of multiple stages or what we call states. -In order to go from one state to the next, the user can specify conditions. -These conditions can be the contiguity of events or a filter condition on an event. - -Each pattern has to start with an initial state: +The pattern API allows you to quickly define complex pattern sequences that you want to extract +from your input stream. + +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for +individual events with the same properties. These simple patterns are called * states *. A complex pattern — End diff – I am aware of the difficulty of naming a single pattern but I am not sure if naming it state is good idea, as internally we use State for something different. Do you think the distinction: pattern <-> pattern sequence is not enough?
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user dawidwys commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119609218

          — Diff: docs/dev/libs/cep.md —
          @@ -215,12 +303,11 @@ start.subtype(classOf[SubEvent]).where(subEvent => ... /* some condition */)
          </div>
          </div>

          -As it can be seen here, the subtype condition can also be combined with an additional filter condition on the subtype.
          -In fact, you can always provide multiple conditions by calling `where` and `subtype` multiple times.
          -These conditions will then be combined using the logical AND operator.
          +*Combining Conditions:* As shown, the `subtype` condition can be combined with additional conditions.
          +In fact, this holds for every condition. You can arbitrarily combine multiple conditions by sequentially calling
          +`where()`. The final result will be the logical *AND* of the results of the individual conditions.

          -In order to construct or conditions, one has to call the `or` method with a respective filter function.
          -Any existing filter function is then ORed with the given one.
          +In order to combine conditions using OR, you can call the `or` method, as shown below.
          — End diff –

          bold the OR (OR -> *OR*)
          `or` -> `or()`

          Show
          githubbot ASF GitHub Bot added a comment - Github user dawidwys commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119609218 — Diff: docs/dev/libs/cep.md — @@ -215,12 +303,11 @@ start.subtype(classOf [SubEvent] ).where(subEvent => ... /* some condition */) </div> </div> -As it can be seen here, the subtype condition can also be combined with an additional filter condition on the subtype. -In fact, you can always provide multiple conditions by calling `where` and `subtype` multiple times. -These conditions will then be combined using the logical AND operator. +* Combining Conditions: * As shown, the `subtype` condition can be combined with additional conditions. +In fact, this holds for every condition. You can arbitrarily combine multiple conditions by sequentially calling +`where()`. The final result will be the logical * AND * of the results of the individual conditions. -In order to construct or conditions, one has to call the `or` method with a respective filter function. -Any existing filter function is then ORed with the given one. +In order to combine conditions using OR , you can call the `or` method, as shown below. — End diff – bold the OR ( OR -> * OR *) `or` -> `or()`
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user dawidwys commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119611549

          — Diff: docs/dev/libs/cep.md —
          @@ -246,63 +333,118 @@ 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 consecutive events:

          -<div class="codetabs" markdown="1">
          -<div data-lang="java" markdown="1">
          -

          {% highlight java %}

          -Pattern<Event, ?> strictNext = start.next("middle");
          -

          {% endhighlight %}
          -</div>
          + 1. Strict Contiguity: which expects all matching events to appear strictly the one after the other,
          + without any non-matching events in-between.

          -<div data-lang="scala" markdown="1">
          -{% highlight scala %}
          -val strictNext: Pattern[Event, _] = start.next("middle")
          -{% endhighlight %}

          -</div>
          -</div>
          + 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.

          -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.
          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.
          — End diff –

          there is `c` between `a1` and `a2`

          Show
          githubbot ASF GitHub Bot added a comment - Github user dawidwys commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119611549 — Diff: docs/dev/libs/cep.md — @@ -246,63 +333,118 @@ 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 consecutive events: -<div class="codetabs" markdown="1"> -<div data-lang="java" markdown="1"> - {% highlight java %} -Pattern<Event, ?> strictNext = start.next("middle"); - {% endhighlight %} -</div> + 1. Strict Contiguity: which expects all matching events to appear strictly the one after the other, + without any non-matching events in-between. -<div data-lang="scala" markdown="1"> -{% highlight scala %} -val strictNext: Pattern [Event, _] = start.next("middle") -{% endhighlight %} -</div> -</div> + 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. -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. 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. — End diff – there is `c` between `a1` and `a2`
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user dawidwys commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119610954

          — Diff: docs/dev/libs/cep.md —
          @@ -246,63 +333,118 @@ 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
          — End diff –

          I would make it a higher level section and changed Conditions on Contiguity -> Contiguity.

          Also I think this is the place where inner contiguity for looping states should be described.

          Show
          githubbot ASF GitHub Bot added a comment - Github user dawidwys commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119610954 — Diff: docs/dev/libs/cep.md — @@ -246,63 +333,118 @@ 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 — End diff – I would make it a higher level section and changed Conditions on Contiguity -> Contiguity. Also I think this is the place where inner contiguity for looping states should be described.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user dawidwys commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119612871

          — Diff: docs/dev/libs/cep.md —
          @@ -246,63 +333,118 @@ 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 consecutive events:

          -<div class="codetabs" markdown="1">
          -<div data-lang="java" markdown="1">
          -

          {% highlight java %}

          -Pattern<Event, ?> strictNext = start.next("middle");
          -

          {% endhighlight %}
          -</div>
          + 1. Strict Contiguity: which expects all matching events to appear strictly the one after the other,
          + without any non-matching events in-between.

          -<div data-lang="scala" markdown="1">
          -{% highlight scala %}
          -val strictNext: Pattern[Event, _] = start.next("middle")
          -{% endhighlight %}

          -</div>
          -</div>
          + 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.

          -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.
          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`.
          +
          — End diff –

          For the examples I would use some additional signs, cause just with the formatting it is hard to read.

          How about:

          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}

          `.

          Show
          githubbot ASF GitHub Bot added a comment - Github user dawidwys commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119612871 — Diff: docs/dev/libs/cep.md — @@ -246,63 +333,118 @@ 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 consecutive events: -<div class="codetabs" markdown="1"> -<div data-lang="java" markdown="1"> - {% highlight java %} -Pattern<Event, ?> strictNext = start.next("middle"); - {% endhighlight %} -</div> + 1. Strict Contiguity: which expects all matching events to appear strictly the one after the other, + without any non-matching events in-between. -<div data-lang="scala" markdown="1"> -{% highlight scala %} -val strictNext: Pattern [Event, _] = start.next("middle") -{% endhighlight %} -</div> -</div> + 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. -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. 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`. + — End diff – For the examples I would use some additional signs, cause just with the formatting it is hard to read. How about: 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} `.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user dawidwys commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119607252

          — Diff: docs/dev/libs/cep.md —
          @@ -98,48 +128,105 @@ val result: DataStream[Alert] = patternStream.select(createAlert(_))
          </div>
          </div>

          -Note that we use Java 8 lambdas in our Java code examples to make them more succinct.
          -

            1. The Pattern API

          -The pattern API allows you to quickly define complex event patterns.
          -
          -Each pattern consists of multiple stages or what we call states.
          -In order to go from one state to the next, the user can specify conditions.
          -These conditions can be the contiguity of events or a filter condition on an event.
          -
          -Each pattern has to start with an initial state:
          +The pattern API allows you to quickly define complex pattern sequences that you want to extract
          +from your input stream.
          +
          +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for
          +individual events with the same properties. These simple patterns are called *states*. A complex pattern
          +can be seen as a graph of such states, where transition from one state to the next happens based on user-specified
          +conditions, e.g. `event.getName().equals("start")`. A match is a sequence of input events which visit all
          +states of the complex pattern graph, through a sequence of valid state transitions.
          +
          +<span class="label label-danger">Attention</span> Each state must have a unique name to identify the matched
          +events later on.
          +
          +<span class="label label-danger">Attention</span> State names *CANNOT* contain the character `:`.
          +
          +In the remainder, we start by describing how to define [States](#states), before describing how you can
          +combine individual states into [Complex Patterns](#combining-states).
          +
          +### Individual States
          +
          +A *State* can be either a singleton state, or a looping one. Singleton states accept a single event,
          while looping ones accept more than one. In pattern matching symbols, in the pattern `a b c? d` (or `a`,
          +followed by one or more `b`'s, optionally followed by a `c`, followed by a `d`), `a`, `c?`, and `d` are
          singleton patterns, while `b` is a looping one (see [Quantifiers](#quantifiers)). In addition, each state
          +can have one or more conditions based on which it accepts events (see [Conditions](#conditions)).
          +
          +#### Quantifiers
          +
          +In FlinkCEP, looping patterns can be specified using the methods: `pattern.oneOrMore()`, for states that expect one or
          more occurrences of a given event (e.g. the `b` mentioned previously), and `pattern.times(#ofTimes)` for states that
          +expect a specific number of occurrences of a given type of event, e.g. 4 `a`'s. All states, looping or not, can be made
          +optional using the `pattern.optional()` method. For a state named `start`, the following are valid quantifiers:
          +
          + <div class="codetabs" markdown="1">
          + <div data-lang="java" markdown="1">
          +

          {% highlight java %}

          + // expecting 4 occurrences
          + start.times(4);
          +
          + // expecting 0 or 4 occurrences
          + start.times(4).optional();
          +
          + // expecting 1 or more occurrences
          + start.oneOrMore();
          +
          + // expecting 0 or more occurrences
          + start.oneOrMore().optional();
          +

          {% endhighlight %}
          + </div>
          +
          + <div data-lang="scala" markdown="1">
          + {% highlight scala %}
          + // expecting 4 occurrences
          + start.times(4)
          +
          + // expecting 0 or 4 occurrences
          + start.times(4).optional()
          +
          + // expecting 1 or more occurrences
          + start.oneOrMore()
          +
          + // expecting 0 or more occurrences
          + start.oneOrMore().optional()
          + {% endhighlight %}

          + </div>
          + </div>
          +
          +#### Conditions
          +
          +At every state, and in order to go from one state to the next, you can specify additional *conditions*.
          +These conditions can be related to:
          +
          + 1. a [property of the incoming event](#conditions-on-properties), e.g. its value should be larger than 5,
          + or larger than the average value of the previously accepted events.
          +
          + 2. the [contiguity of the matching events](#conditions-on-contiguity), e.g. detect pattern `a,b,c` without
          — End diff –

          I would move this to the combining patterns section. It is easier to reason about after understanding the contiguity between single patterns/states.

          Show
          githubbot ASF GitHub Bot added a comment - Github user dawidwys commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119607252 — Diff: docs/dev/libs/cep.md — @@ -98,48 +128,105 @@ val result: DataStream [Alert] = patternStream.select(createAlert(_)) </div> </div> -Note that we use Java 8 lambdas in our Java code examples to make them more succinct. - The Pattern API -The pattern API allows you to quickly define complex event patterns. - -Each pattern consists of multiple stages or what we call states. -In order to go from one state to the next, the user can specify conditions. -These conditions can be the contiguity of events or a filter condition on an event. - -Each pattern has to start with an initial state: +The pattern API allows you to quickly define complex pattern sequences that you want to extract +from your input stream. + +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for +individual events with the same properties. These simple patterns are called * states *. A complex pattern +can be seen as a graph of such states, where transition from one state to the next happens based on user-specified + conditions , e.g. `event.getName().equals("start")`. A match is a sequence of input events which visit all +states of the complex pattern graph, through a sequence of valid state transitions. + +<span class="label label-danger">Attention</span> Each state must have a unique name to identify the matched +events later on. + +<span class="label label-danger">Attention</span> State names * CANNOT * contain the character `:`. + +In the remainder, we start by describing how to define [States] (#states), before describing how you can +combine individual states into [Complex Patterns] (#combining-states). + +### Individual States + +A * State * can be either a singleton state, or a looping one. Singleton states accept a single event, while looping ones accept more than one. In pattern matching symbols, in the pattern `a b c? d` (or `a`, +followed by one or more `b`'s, optionally followed by a `c`, followed by a `d`), `a`, `c?`, and `d` are singleton patterns, while `b ` is a looping one (see [Quantifiers] (#quantifiers)). In addition, each state +can have one or more conditions based on which it accepts events (see [Conditions] (#conditions)). + +#### Quantifiers + +In FlinkCEP, looping patterns can be specified using the methods: `pattern.oneOrMore()`, for states that expect one or more occurrences of a given event (e.g. the `b ` mentioned previously), and `pattern.times(#ofTimes)` for states that +expect a specific number of occurrences of a given type of event, e.g. 4 `a`'s. All states, looping or not, can be made +optional using the `pattern.optional()` method. For a state named `start`, the following are valid quantifiers: + + <div class="codetabs" markdown="1"> + <div data-lang="java" markdown="1"> + {% highlight java %} + // expecting 4 occurrences + start.times(4); + + // expecting 0 or 4 occurrences + start.times(4).optional(); + + // expecting 1 or more occurrences + start.oneOrMore(); + + // expecting 0 or more occurrences + start.oneOrMore().optional(); + {% endhighlight %} + </div> + + <div data-lang="scala" markdown="1"> + {% highlight scala %} + // expecting 4 occurrences + start.times(4) + + // expecting 0 or 4 occurrences + start.times(4).optional() + + // expecting 1 or more occurrences + start.oneOrMore() + + // expecting 0 or more occurrences + start.oneOrMore().optional() + {% endhighlight %} + </div> + </div> + +#### Conditions + +At every state, and in order to go from one state to the next, you can specify additional * conditions *. +These conditions can be related to: + + 1. a [property of the incoming event] (#conditions-on-properties), e.g. its value should be larger than 5, + or larger than the average value of the previously accepted events. + + 2. the [contiguity of the matching events] (#conditions-on-contiguity), e.g. detect pattern `a,b,c` without — End diff – I would move this to the combining patterns section. It is easier to reason about after understanding the contiguity between single patterns/states.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user dawidwys commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119603232

          — Diff: docs/dev/libs/cep.md —
          @@ -23,22 +23,24 @@ specific language governing permissions and limitations
          under the License.
          -->

          -FlinkCEP is the complex event processing library for Flink.
          -It allows you to easily detect complex event patterns in a stream of endless data.
          -Complex events can then be constructed from matching sequences.
          -This gives you the opportunity to quickly get hold of what's really important in your data.
          +FlinkCEP is the Complex Event Processing (CEP) library implemented on top of Flink.
          +It allows you to easily detect event patterns in an endless stream of events, thus
          +giving you the opportunity to quickly get hold of what's really important in your
          +data.

          -<span class="label label-danger">Attention</span> The events in the `DataStream` to which
          -you want to apply pattern matching have to implement proper `equals()` and `hashCode()` methods
          -because these are used for comparing and matching events.
          +This page described the API calls available in Flink CEP. We start by presenting the [Pattern API](#the-pattern-api),
          — End diff –

          This page described -> This page describes

          Show
          githubbot ASF GitHub Bot added a comment - Github user dawidwys commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119603232 — Diff: docs/dev/libs/cep.md — @@ -23,22 +23,24 @@ specific language governing permissions and limitations under the License. --> -FlinkCEP is the complex event processing library for Flink. -It allows you to easily detect complex event patterns in a stream of endless data. -Complex events can then be constructed from matching sequences. -This gives you the opportunity to quickly get hold of what's really important in your data. +FlinkCEP is the Complex Event Processing (CEP) library implemented on top of Flink. +It allows you to easily detect event patterns in an endless stream of events, thus +giving you the opportunity to quickly get hold of what's really important in your +data. -<span class="label label-danger">Attention</span> The events in the `DataStream` to which -you want to apply pattern matching have to implement proper `equals()` and `hashCode()` methods -because these are used for comparing and matching events. +This page described the API calls available in Flink CEP. We start by presenting the [Pattern API] (#the-pattern-api), — End diff – This page described -> This page describes
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user dawidwys commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119613118

          — Diff: docs/dev/libs/cep.md —
          @@ -246,63 +333,118 @@ 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 consecutive events:

          -<div class="codetabs" markdown="1">
          -<div data-lang="java" markdown="1">
          -

          {% highlight java %}

          -Pattern<Event, ?> strictNext = start.next("middle");
          -

          {% endhighlight %}
          -</div>
          + 1. Strict Contiguity: which expects all matching events to appear strictly the one after the other,
          + without any non-matching events in-between.

          -<div data-lang="scala" markdown="1">
          -{% highlight scala %}
          -val strictNext: Pattern[Event, _] = start.next("middle")
          -{% endhighlight %}

          -</div>
          -</div>
          + 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.

          -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.
          To illustrate the above with an example, a pattern sequence `a b` (one or more `a`s followed by a `b`) with
          — End diff –

          First I would start with example without looping state, as we silently introduce the internal continuity.

          Show
          githubbot ASF GitHub Bot added a comment - Github user dawidwys commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119613118 — Diff: docs/dev/libs/cep.md — @@ -246,63 +333,118 @@ 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 consecutive events: -<div class="codetabs" markdown="1"> -<div data-lang="java" markdown="1"> - {% highlight java %} -Pattern<Event, ?> strictNext = start.next("middle"); - {% endhighlight %} -</div> + 1. Strict Contiguity: which expects all matching events to appear strictly the one after the other, + without any non-matching events in-between. -<div data-lang="scala" markdown="1"> -{% highlight scala %} -val strictNext: Pattern [Event, _] = start.next("middle") -{% endhighlight %} -</div> -</div> + 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. -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. To illustrate the above with an example, a pattern sequence `a b` (one or more `a`s followed by a `b`) with — End diff – First I would start with example without looping state, as we silently introduce the internal continuity.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user dawidwys commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119608577

          — Diff: docs/dev/libs/cep.md —
          @@ -98,48 +128,105 @@ val result: DataStream[Alert] = patternStream.select(createAlert(_))
          </div>
          </div>

          -Note that we use Java 8 lambdas in our Java code examples to make them more succinct.
          -

            1. The Pattern API

          -The pattern API allows you to quickly define complex event patterns.
          -
          -Each pattern consists of multiple stages or what we call states.
          -In order to go from one state to the next, the user can specify conditions.
          -These conditions can be the contiguity of events or a filter condition on an event.
          -
          -Each pattern has to start with an initial state:
          +The pattern API allows you to quickly define complex pattern sequences that you want to extract
          +from your input stream.
          +
          +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for
          +individual events with the same properties. These simple patterns are called *states*. A complex pattern
          +can be seen as a graph of such states, where transition from one state to the next happens based on user-specified
          +conditions, e.g. `event.getName().equals("start")`. A match is a sequence of input events which visit all
          +states of the complex pattern graph, through a sequence of valid state transitions.
          +
          +<span class="label label-danger">Attention</span> Each state must have a unique name to identify the matched
          +events later on.
          +
          +<span class="label label-danger">Attention</span> State names *CANNOT* contain the character `:`.
          +
          +In the remainder, we start by describing how to define [States](#states), before describing how you can
          +combine individual states into [Complex Patterns](#combining-states).
          +
          +### Individual States
          +
          +A *State* can be either a singleton state, or a looping one. Singleton states accept a single event,
          while looping ones accept more than one. In pattern matching symbols, in the pattern `a b c? d` (or `a`,
          +followed by one or more `b`'s, optionally followed by a `c`, followed by a `d`), `a`, `c?`, and `d` are
          singleton patterns, while `b` is a looping one (see [Quantifiers](#quantifiers)). In addition, each state
          +can have one or more conditions based on which it accepts events (see [Conditions](#conditions)).
          +
          +#### Quantifiers
          +
          +In FlinkCEP, looping patterns can be specified using the methods: `pattern.oneOrMore()`, for states that expect one or
          more occurrences of a given event (e.g. the `b` mentioned previously), and `pattern.times(#ofTimes)` for states that
          +expect a specific number of occurrences of a given type of event, e.g. 4 `a`'s. All states, looping or not, can be made
          +optional using the `pattern.optional()` method. For a state named `start`, the following are valid quantifiers:
          +
          + <div class="codetabs" markdown="1">
          + <div data-lang="java" markdown="1">
          +

          {% highlight java %}

          + // expecting 4 occurrences
          + start.times(4);
          +
          + // expecting 0 or 4 occurrences
          + start.times(4).optional();
          +
          + // expecting 1 or more occurrences
          + start.oneOrMore();
          +
          + // expecting 0 or more occurrences
          + start.oneOrMore().optional();
          +

          {% endhighlight %}
          + </div>
          +
          + <div data-lang="scala" markdown="1">
          + {% highlight scala %}
          + // expecting 4 occurrences
          + start.times(4)
          +
          + // expecting 0 or 4 occurrences
          + start.times(4).optional()
          +
          + // expecting 1 or more occurrences
          + start.oneOrMore()
          +
          + // expecting 0 or more occurrences
          + start.oneOrMore().optional()
          + {% endhighlight %}

          + </div>
          + </div>
          +
          +#### Conditions
          +
          +At every state, and in order to go from one state to the next, you can specify additional *conditions*.
          +These conditions can be related to:
          +
          + 1. a [property of the incoming event](#conditions-on-properties), e.g. its value should be larger than 5,
          + or larger than the average value of the previously accepted events.
          +
          + 2. the [contiguity of the matching events](#conditions-on-contiguity), e.g. detect pattern `a,b,c` without
          + non-matching events between any matching ones.
          +
          The latter refers to "looping" states, i.e. states that can accept more than one event, e.g. the `b` in `a b+ c`,
          +which searches for one or more `b`'s.
          +
          +##### Conditions on Properties
          +
          +Conditions on the event properties can be specified via the `pattern.where()` method. These can be either
          +`IterativeCondition`s or `SimpleCondition`s.
          +
          +*Iterative Conditions:* This is the most general type of conditions. This allows to specify a condition that accepts
          +any subsequent event based on some statistic over a subset of the previously accepted events.
          — End diff –

          based on properties of the previously accepted events or even some statistic over a subset of them.

          This way we emphasize that we can take into account for example just the previous event.

          Show
          githubbot ASF GitHub Bot added a comment - Github user dawidwys commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119608577 — Diff: docs/dev/libs/cep.md — @@ -98,48 +128,105 @@ val result: DataStream [Alert] = patternStream.select(createAlert(_)) </div> </div> -Note that we use Java 8 lambdas in our Java code examples to make them more succinct. - The Pattern API -The pattern API allows you to quickly define complex event patterns. - -Each pattern consists of multiple stages or what we call states. -In order to go from one state to the next, the user can specify conditions. -These conditions can be the contiguity of events or a filter condition on an event. - -Each pattern has to start with an initial state: +The pattern API allows you to quickly define complex pattern sequences that you want to extract +from your input stream. + +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for +individual events with the same properties. These simple patterns are called * states *. A complex pattern +can be seen as a graph of such states, where transition from one state to the next happens based on user-specified + conditions , e.g. `event.getName().equals("start")`. A match is a sequence of input events which visit all +states of the complex pattern graph, through a sequence of valid state transitions. + +<span class="label label-danger">Attention</span> Each state must have a unique name to identify the matched +events later on. + +<span class="label label-danger">Attention</span> State names * CANNOT * contain the character `:`. + +In the remainder, we start by describing how to define [States] (#states), before describing how you can +combine individual states into [Complex Patterns] (#combining-states). + +### Individual States + +A * State * can be either a singleton state, or a looping one. Singleton states accept a single event, while looping ones accept more than one. In pattern matching symbols, in the pattern `a b c? d` (or `a`, +followed by one or more `b`'s, optionally followed by a `c`, followed by a `d`), `a`, `c?`, and `d` are singleton patterns, while `b ` is a looping one (see [Quantifiers] (#quantifiers)). In addition, each state +can have one or more conditions based on which it accepts events (see [Conditions] (#conditions)). + +#### Quantifiers + +In FlinkCEP, looping patterns can be specified using the methods: `pattern.oneOrMore()`, for states that expect one or more occurrences of a given event (e.g. the `b ` mentioned previously), and `pattern.times(#ofTimes)` for states that +expect a specific number of occurrences of a given type of event, e.g. 4 `a`'s. All states, looping or not, can be made +optional using the `pattern.optional()` method. For a state named `start`, the following are valid quantifiers: + + <div class="codetabs" markdown="1"> + <div data-lang="java" markdown="1"> + {% highlight java %} + // expecting 4 occurrences + start.times(4); + + // expecting 0 or 4 occurrences + start.times(4).optional(); + + // expecting 1 or more occurrences + start.oneOrMore(); + + // expecting 0 or more occurrences + start.oneOrMore().optional(); + {% endhighlight %} + </div> + + <div data-lang="scala" markdown="1"> + {% highlight scala %} + // expecting 4 occurrences + start.times(4) + + // expecting 0 or 4 occurrences + start.times(4).optional() + + // expecting 1 or more occurrences + start.oneOrMore() + + // expecting 0 or more occurrences + start.oneOrMore().optional() + {% endhighlight %} + </div> + </div> + +#### Conditions + +At every state, and in order to go from one state to the next, you can specify additional * conditions *. +These conditions can be related to: + + 1. a [property of the incoming event] (#conditions-on-properties), e.g. its value should be larger than 5, + or larger than the average value of the previously accepted events. + + 2. the [contiguity of the matching events] (#conditions-on-contiguity), e.g. detect pattern `a,b,c` without + non-matching events between any matching ones. + The latter refers to "looping" states, i.e. states that can accept more than one event, e.g. the `b ` in `a b+ c`, +which searches for one or more `b`'s. + +##### Conditions on Properties + +Conditions on the event properties can be specified via the `pattern.where()` method. These can be either +`IterativeCondition`s or `SimpleCondition`s. + +* Iterative Conditions: * This is the most general type of conditions. This allows to specify a condition that accepts +any subsequent event based on some statistic over a subset of the previously accepted events. — End diff – based on properties of the previously accepted events or even some statistic over a subset of them. This way we emphasize that we can take into account for example just the previous event.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user dawidwys commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119607780

          — Diff: docs/dev/libs/cep.md —
          @@ -98,48 +128,105 @@ val result: DataStream[Alert] = patternStream.select(createAlert(_))
          </div>
          </div>

          -Note that we use Java 8 lambdas in our Java code examples to make them more succinct.
          -

            1. The Pattern API

          -The pattern API allows you to quickly define complex event patterns.
          -
          -Each pattern consists of multiple stages or what we call states.
          -In order to go from one state to the next, the user can specify conditions.
          -These conditions can be the contiguity of events or a filter condition on an event.
          -
          -Each pattern has to start with an initial state:
          +The pattern API allows you to quickly define complex pattern sequences that you want to extract
          +from your input stream.
          +
          +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for
          +individual events with the same properties. These simple patterns are called *states*. A complex pattern
          +can be seen as a graph of such states, where transition from one state to the next happens based on user-specified
          +conditions, e.g. `event.getName().equals("start")`. A match is a sequence of input events which visit all
          +states of the complex pattern graph, through a sequence of valid state transitions.
          +
          +<span class="label label-danger">Attention</span> Each state must have a unique name to identify the matched
          +events later on.
          +
          +<span class="label label-danger">Attention</span> State names *CANNOT* contain the character `:`.
          +
          +In the remainder, we start by describing how to define [States](#states), before describing how you can
          +combine individual states into [Complex Patterns](#combining-states).
          +
          +### Individual States
          +
          +A *State* can be either a singleton state, or a looping one. Singleton states accept a single event,
          while looping ones accept more than one. In pattern matching symbols, in the pattern `a b c? d` (or `a`,
          +followed by one or more `b`'s, optionally followed by a `c`, followed by a `d`), `a`, `c?`, and `d` are
          singleton patterns, while `b` is a looping one (see [Quantifiers](#quantifiers)). In addition, each state
          +can have one or more conditions based on which it accepts events (see [Conditions](#conditions)).
          +
          +#### Quantifiers
          +
          +In FlinkCEP, looping patterns can be specified using the methods: `pattern.oneOrMore()`, for states that expect one or
          more occurrences of a given event (e.g. the `b` mentioned previously), and `pattern.times(#ofTimes)` for states that
          +expect a specific number of occurrences of a given type of event, e.g. 4 `a`'s. All states, looping or not, can be made
          +optional using the `pattern.optional()` method. For a state named `start`, the following are valid quantifiers:
          +
          + <div class="codetabs" markdown="1">
          + <div data-lang="java" markdown="1">
          +

          {% highlight java %}

          + // expecting 4 occurrences
          + start.times(4);
          +
          + // expecting 0 or 4 occurrences
          + start.times(4).optional();
          +
          + // expecting 1 or more occurrences
          + start.oneOrMore();
          +
          + // expecting 0 or more occurrences
          + start.oneOrMore().optional();
          +

          {% endhighlight %}
          + </div>
          +
          + <div data-lang="scala" markdown="1">
          + {% highlight scala %}
          + // expecting 4 occurrences
          + start.times(4)
          +
          + // expecting 0 or 4 occurrences
          + start.times(4).optional()
          +
          + // expecting 1 or more occurrences
          + start.oneOrMore()
          +
          + // expecting 0 or more occurrences
          + start.oneOrMore().optional()
          + {% endhighlight %}

          + </div>
          + </div>
          +
          +#### Conditions
          +
          +At every state, and in order to go from one state to the next, you can specify additional *conditions*.
          +These conditions can be related to:
          +
          + 1. a [property of the incoming event](#conditions-on-properties), e.g. its value should be larger than 5,
          + or larger than the average value of the previously accepted events.
          +
          + 2. the [contiguity of the matching events](#conditions-on-contiguity), e.g. detect pattern `a,b,c` without
          + non-matching events between any matching ones.
          +
          The latter refers to "looping" states, i.e. states that can accept more than one event, e.g. the `b` in `a b+ c`,
          +which searches for one or more `b`'s.
          +
          +##### Conditions on Properties
          +
          +Conditions on the event properties can be specified via the `pattern.where()` method. These can be either
          — End diff –

          Conditions on the event properties can be specified via the `pattern.where()` *and `pattern.or()`* method

          Show
          githubbot ASF GitHub Bot added a comment - Github user dawidwys commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119607780 — Diff: docs/dev/libs/cep.md — @@ -98,48 +128,105 @@ val result: DataStream [Alert] = patternStream.select(createAlert(_)) </div> </div> -Note that we use Java 8 lambdas in our Java code examples to make them more succinct. - The Pattern API -The pattern API allows you to quickly define complex event patterns. - -Each pattern consists of multiple stages or what we call states. -In order to go from one state to the next, the user can specify conditions. -These conditions can be the contiguity of events or a filter condition on an event. - -Each pattern has to start with an initial state: +The pattern API allows you to quickly define complex pattern sequences that you want to extract +from your input stream. + +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for +individual events with the same properties. These simple patterns are called * states *. A complex pattern +can be seen as a graph of such states, where transition from one state to the next happens based on user-specified + conditions , e.g. `event.getName().equals("start")`. A match is a sequence of input events which visit all +states of the complex pattern graph, through a sequence of valid state transitions. + +<span class="label label-danger">Attention</span> Each state must have a unique name to identify the matched +events later on. + +<span class="label label-danger">Attention</span> State names * CANNOT * contain the character `:`. + +In the remainder, we start by describing how to define [States] (#states), before describing how you can +combine individual states into [Complex Patterns] (#combining-states). + +### Individual States + +A * State * can be either a singleton state, or a looping one. Singleton states accept a single event, while looping ones accept more than one. In pattern matching symbols, in the pattern `a b c? d` (or `a`, +followed by one or more `b`'s, optionally followed by a `c`, followed by a `d`), `a`, `c?`, and `d` are singleton patterns, while `b ` is a looping one (see [Quantifiers] (#quantifiers)). In addition, each state +can have one or more conditions based on which it accepts events (see [Conditions] (#conditions)). + +#### Quantifiers + +In FlinkCEP, looping patterns can be specified using the methods: `pattern.oneOrMore()`, for states that expect one or more occurrences of a given event (e.g. the `b ` mentioned previously), and `pattern.times(#ofTimes)` for states that +expect a specific number of occurrences of a given type of event, e.g. 4 `a`'s. All states, looping or not, can be made +optional using the `pattern.optional()` method. For a state named `start`, the following are valid quantifiers: + + <div class="codetabs" markdown="1"> + <div data-lang="java" markdown="1"> + {% highlight java %} + // expecting 4 occurrences + start.times(4); + + // expecting 0 or 4 occurrences + start.times(4).optional(); + + // expecting 1 or more occurrences + start.oneOrMore(); + + // expecting 0 or more occurrences + start.oneOrMore().optional(); + {% endhighlight %} + </div> + + <div data-lang="scala" markdown="1"> + {% highlight scala %} + // expecting 4 occurrences + start.times(4) + + // expecting 0 or 4 occurrences + start.times(4).optional() + + // expecting 1 or more occurrences + start.oneOrMore() + + // expecting 0 or more occurrences + start.oneOrMore().optional() + {% endhighlight %} + </div> + </div> + +#### Conditions + +At every state, and in order to go from one state to the next, you can specify additional * conditions *. +These conditions can be related to: + + 1. a [property of the incoming event] (#conditions-on-properties), e.g. its value should be larger than 5, + or larger than the average value of the previously accepted events. + + 2. the [contiguity of the matching events] (#conditions-on-contiguity), e.g. detect pattern `a,b,c` without + non-matching events between any matching ones. + The latter refers to "looping" states, i.e. states that can accept more than one event, e.g. the `b ` in `a b+ c`, +which searches for one or more `b`'s. + +##### Conditions on Properties + +Conditions on the event properties can be specified via the `pattern.where()` method. These can be either — End diff – Conditions on the event properties can be specified via the `pattern.where()` * and `pattern.or()` * method
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user dawidwys commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119616280

          — Diff: docs/dev/libs/cep.md —
          @@ -246,63 +333,118 @@ 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 consecutive events:

          -<div class="codetabs" markdown="1">
          -<div data-lang="java" markdown="1">
          -

          {% highlight java %}
          -Pattern<Event, ?> strictNext = start.next("middle");
          -{% endhighlight %}
          -</div>
          + 1. Strict Contiguity: which expects all matching events to appear strictly the one after the other,
          + without any non-matching events in-between.

          -<div data-lang="scala" markdown="1">
          -{% highlight scala %}
          -val strictNext: Pattern[Event, _] = start.next("middle")
          -{% endhighlight %}
          -</div>
          -</div>
          + 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.

          -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.
          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`.
          +
          +Contiguity conditions should be specified both within individual (looping) states but also
          +across states. 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.
          +
          +### 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.
          +
          +Finally, it is also possible to define a temporal constraint for the pattern to be valid.
          — End diff –

          I would emphasize it applies whole pattern sequence. And if multiple within are applied (even for different states/parts) the shortes one is picked up.

          Show
          githubbot ASF GitHub Bot added a comment - Github user dawidwys commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119616280 — Diff: docs/dev/libs/cep.md — @@ -246,63 +333,118 @@ 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 consecutive events: -<div class="codetabs" markdown="1"> -<div data-lang="java" markdown="1"> - {% highlight java %} -Pattern<Event, ?> strictNext = start.next("middle"); -{% endhighlight %} -</div> + 1. Strict Contiguity: which expects all matching events to appear strictly the one after the other, + without any non-matching events in-between. -<div data-lang="scala" markdown="1"> -{% highlight scala %} -val strictNext: Pattern [Event, _] = start.next("middle") -{% endhighlight %} -</div> -</div> + 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. -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. 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`. + +Contiguity conditions should be specified both within individual (looping) states but also +across states. 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. + +### 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. + +Finally, it is also possible to define a temporal constraint for the pattern to be valid. — End diff – I would emphasize it applies whole pattern sequence. And if multiple within are applied (even for different states/parts) the shortes one is picked up.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user rmetzger commented on the issue:

          https://github.com/apache/flink/pull/4041

          @dawidwys Do you think we can merge the updated documentation today already?
          I would like to put out the 1.3 release ann with a link to the CEP docs.

          Show
          githubbot ASF GitHub Bot added a comment - Github user rmetzger commented on the issue: https://github.com/apache/flink/pull/4041 @dawidwys Do you think we can merge the updated documentation today already? I would like to put out the 1.3 release ann with a link to the CEP docs.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user dawidwys commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119618715

          — Diff: docs/dev/libs/cep.md —
          @@ -98,48 +128,105 @@ val result: DataStream[Alert] = patternStream.select(createAlert(_))
          </div>
          </div>

          -Note that we use Java 8 lambdas in our Java code examples to make them more succinct.
          -

            1. The Pattern API

          -The pattern API allows you to quickly define complex event patterns.
          -
          -Each pattern consists of multiple stages or what we call states.
          -In order to go from one state to the next, the user can specify conditions.
          -These conditions can be the contiguity of events or a filter condition on an event.
          -
          -Each pattern has to start with an initial state:
          +The pattern API allows you to quickly define complex pattern sequences that you want to extract
          +from your input stream.
          +
          +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for
          +individual events with the same properties. These simple patterns are called *states*. A complex pattern
          +can be seen as a graph of such states, where transition from one state to the next happens based on user-specified
          +conditions, e.g. `event.getName().equals("start")`. A match is a sequence of input events which visit all
          +states of the complex pattern graph, through a sequence of valid state transitions.
          +
          +<span class="label label-danger">Attention</span> Each state must have a unique name to identify the matched
          +events later on.
          +
          +<span class="label label-danger">Attention</span> State names *CANNOT* contain the character `:`.
          +
          +In the remainder, we start by describing how to define [States](#states), before describing how you can
          +combine individual states into [Complex Patterns](#combining-states).
          +
          +### Individual States
          +
          +A *State* can be either a singleton state, or a looping one. Singleton states accept a single event,
          while looping ones accept more than one. In pattern matching symbols, in the pattern `a b c? d` (or `a`,
          — End diff –

          The sentence starting with "In pattern matchin" was hard to understand for me.

          How about?:
          In regex style symbols, in the pattern:
          > `a b+ c? d`

          or in more FLinkCEP style:
          > ( `a`, followed by one or more `b`'s, optionally followed by a `c`, followed by a `d`),

          `a`, `c?`, and `d` are singleton patterns, while `b+` is a looping one (see [Quantifiers](#quantifiers)).

          Show
          githubbot ASF GitHub Bot added a comment - Github user dawidwys commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119618715 — Diff: docs/dev/libs/cep.md — @@ -98,48 +128,105 @@ val result: DataStream [Alert] = patternStream.select(createAlert(_)) </div> </div> -Note that we use Java 8 lambdas in our Java code examples to make them more succinct. - The Pattern API -The pattern API allows you to quickly define complex event patterns. - -Each pattern consists of multiple stages or what we call states. -In order to go from one state to the next, the user can specify conditions. -These conditions can be the contiguity of events or a filter condition on an event. - -Each pattern has to start with an initial state: +The pattern API allows you to quickly define complex pattern sequences that you want to extract +from your input stream. + +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for +individual events with the same properties. These simple patterns are called * states *. A complex pattern +can be seen as a graph of such states, where transition from one state to the next happens based on user-specified + conditions , e.g. `event.getName().equals("start")`. A match is a sequence of input events which visit all +states of the complex pattern graph, through a sequence of valid state transitions. + +<span class="label label-danger">Attention</span> Each state must have a unique name to identify the matched +events later on. + +<span class="label label-danger">Attention</span> State names * CANNOT * contain the character `:`. + +In the remainder, we start by describing how to define [States] (#states), before describing how you can +combine individual states into [Complex Patterns] (#combining-states). + +### Individual States + +A * State * can be either a singleton state, or a looping one. Singleton states accept a single event, while looping ones accept more than one. In pattern matching symbols, in the pattern `a b c? d` (or `a`, — End diff – The sentence starting with "In pattern matchin" was hard to understand for me. How about?: In regex style symbols, in the pattern: > `a b+ c? d` or in more FLinkCEP style: > ( `a`, followed by one or more `b`'s, optionally followed by a `c`, followed by a `d`), `a`, `c?`, and `d` are singleton patterns, while `b+` is a looping one (see [Quantifiers] (#quantifiers)).
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user dawidwys commented on the issue:

          https://github.com/apache/flink/pull/4041

          In fact I managed to finish the review. Generally the docs look great! Congrats on the hard work @kl0u!

          @rmetzger Most of the comments I had were to the formatting/reordering, the only bigger concern is the naming of the State. All in all I think it can be merged today.

          Show
          githubbot ASF GitHub Bot added a comment - Github user dawidwys commented on the issue: https://github.com/apache/flink/pull/4041 In fact I managed to finish the review. Generally the docs look great! Congrats on the hard work @kl0u! @rmetzger Most of the comments I had were to the formatting/reordering, the only bigger concern is the naming of the State. All in all I think it can be merged today.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user rmetzger commented on the issue:

          https://github.com/apache/flink/pull/4041

          Cool, thx

          Show
          githubbot ASF GitHub Bot added a comment - Github user rmetzger commented on the issue: https://github.com/apache/flink/pull/4041 Cool, thx
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user kl0u commented on the issue:

          https://github.com/apache/flink/pull/4041

          Thanks a lot @dawidwys for having a detailed look at it! I will integrate your comments and then merge.

          Show
          githubbot ASF GitHub Bot added a comment - Github user kl0u commented on the issue: https://github.com/apache/flink/pull/4041 Thanks a lot @dawidwys for having a detailed look at it! I will integrate your comments and then merge.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user rmetzger commented on the issue:

          https://github.com/apache/flink/pull/4041

          I'll update the release announcement blog post, once the CEP doc has been updated

          Show
          githubbot ASF GitHub Bot added a comment - Github user rmetzger commented on the issue: https://github.com/apache/flink/pull/4041 I'll update the release announcement blog post, once the CEP doc has been updated
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user alpinegizmo commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119878726

          — Diff: docs/dev/libs/cep.md —
          @@ -168,33 +256,34 @@ start.where(
          </div>
          </div>

          -<span class="label label-danger">Attention</span> The call to `Context.getEventsForPattern(...)` has to find the
          -elements that belong to the pattern. The cost of this operation can vary, so when implementing your condition, try
          -to minimize the times the method is called.
          +<span class="label label-danger">Attention</span> The call to `context.getEventsForPattern(...)` finds all the
          +previously accepted events for a given potential match. The cost of this operation can vary, so when implementing
          +your condition, try to minimize the times the method is called.
          — End diff –

          ... try to minimize its use.

          Show
          githubbot ASF GitHub Bot added a comment - Github user alpinegizmo commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119878726 — Diff: docs/dev/libs/cep.md — @@ -168,33 +256,34 @@ start.where( </div> </div> -<span class="label label-danger">Attention</span> The call to `Context.getEventsForPattern(...)` has to find the -elements that belong to the pattern. The cost of this operation can vary, so when implementing your condition, try -to minimize the times the method is called. +<span class="label label-danger">Attention</span> The call to `context.getEventsForPattern(...)` finds all the +previously accepted events for a given potential match. The cost of this operation can vary, so when implementing +your condition, try to minimize the times the method is called. — End diff – ... try to minimize its use.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user alpinegizmo commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119885420

          — 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.
          — End diff –

          Non-Deterministic Relaxed Contiguity is hard to understand. Maybe this is clearer:

          ... which further relaxes contiguity, allowing additional matches that ignore some matching events.

          Show
          githubbot ASF GitHub Bot added a comment - Github user alpinegizmo commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119885420 — 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. — End diff – Non-Deterministic Relaxed Contiguity is hard to understand. Maybe this is clearer: ... which further relaxes contiguity, allowing additional matches that ignore some matching events.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user alpinegizmo commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119883183

          — Diff: docs/dev/libs/cep.md —
          @@ -98,48 +128,106 @@ val result: DataStream[Alert] = patternStream.select(createAlert(_))
          </div>
          </div>

          -Note that we use Java 8 lambdas in our Java code examples to make them more succinct.
          -

            1. The Pattern API

          -The pattern API allows you to quickly define complex event patterns.
          -
          -Each pattern consists of multiple stages or what we call states.
          -In order to go from one state to the next, the user can specify conditions.
          -These conditions can be the contiguity of events or a filter condition on an event.
          -
          -Each pattern has to start with an initial state:
          -
          -<div class="codetabs" markdown="1">
          -<div data-lang="java" markdown="1">
          -

          {% highlight java %}

          -Pattern<Event, ?> start = Pattern.<Event>begin("start");
          -

          {% endhighlight %}
          -</div>
          -
          -<div data-lang="scala" markdown="1">
          -{% highlight scala %}
          -val start : Pattern[Event, _] = Pattern.begin("start")
          -{% endhighlight %}

          -</div>
          -</div>
          -
          -Each state must have a unique name to identify the matched events later on.
          -Additionally, we can specify a filter condition for the event to be accepted as the start event via the `where` method.
          -These filtering conditions can be either an `IterativeCondition` or a `SimpleCondition`.
          -
          -*Iterative Conditions:* This type of conditions can iterate over the previously accepted elements in the pattern and
          -decide to accept a new element or not, based on some statistic over those elements.
          -
          -Below is the code for an iterative condition that accepts elements whose name start with "foo" and for which, the sum
          -of the prices of the previously accepted elements for a state named "middle", plus the price of the current event, do
          -not exceed the value of 5.0. Iterative condition can be very powerful, especially in combination with quantifiers, e.g.
          -`oneToMany` or `zeroToMany`.
          +The pattern API allows you to quickly define complex pattern sequences that you want to extract
          +from your input stream.
          +
          +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for
          +individual events with the same properties. These simple patterns are called *states*. A complex pattern
          +can be seen as a graph of such states, where transition from one state to the next happens based on user-specified
          — End diff –

          ... where transitions from one state to the next occur ...

          Show
          githubbot ASF GitHub Bot added a comment - Github user alpinegizmo commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119883183 — Diff: docs/dev/libs/cep.md — @@ -98,48 +128,106 @@ val result: DataStream [Alert] = patternStream.select(createAlert(_)) </div> </div> -Note that we use Java 8 lambdas in our Java code examples to make them more succinct. - The Pattern API -The pattern API allows you to quickly define complex event patterns. - -Each pattern consists of multiple stages or what we call states. -In order to go from one state to the next, the user can specify conditions. -These conditions can be the contiguity of events or a filter condition on an event. - -Each pattern has to start with an initial state: - -<div class="codetabs" markdown="1"> -<div data-lang="java" markdown="1"> - {% highlight java %} -Pattern<Event, ?> start = Pattern.<Event>begin("start"); - {% endhighlight %} -</div> - -<div data-lang="scala" markdown="1"> -{% highlight scala %} -val start : Pattern [Event, _] = Pattern.begin("start") -{% endhighlight %} -</div> -</div> - -Each state must have a unique name to identify the matched events later on. -Additionally, we can specify a filter condition for the event to be accepted as the start event via the `where` method. -These filtering conditions can be either an `IterativeCondition` or a `SimpleCondition`. - -* Iterative Conditions: * This type of conditions can iterate over the previously accepted elements in the pattern and -decide to accept a new element or not, based on some statistic over those elements. - -Below is the code for an iterative condition that accepts elements whose name start with "foo" and for which, the sum -of the prices of the previously accepted elements for a state named "middle", plus the price of the current event, do -not exceed the value of 5.0. Iterative condition can be very powerful, especially in combination with quantifiers, e.g. -`oneToMany` or `zeroToMany`. +The pattern API allows you to quickly define complex pattern sequences that you want to extract +from your input stream. + +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for +individual events with the same properties. These simple patterns are called * states *. A complex pattern +can be seen as a graph of such states, where transition from one state to the next happens based on user-specified — End diff – ... where transitions from one state to the next occur ...
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user alpinegizmo commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119886927

          — Diff: docs/dev/libs/cep.md —
          @@ -700,26 +995,29 @@ class MyPatternFlatSelectFunction<IN, OUT> implements PatternFlatSelectFunction<
          </div>

          <div data-lang="scala" markdown="1">
          -The `select` method takes a selection function as argument, which is called for each matching event sequence.
          -It receives a map of string/event pairs of the matched events.
          -The string is defined by the name of the state to which the event has been matched.
          -The selection function returns exactly one result per call.
          +The `select()` method takes a selection function as argument, which is called for each matching event sequence.
          +It receives a match in the form of `Map[String, Iterable[IN]]` where the key is the name of each state in your pattern
          +sequence and the value is an Iterable over all accepted events for that state (`IN` is the type of your input elements).
          +The events for a given state are ordered by timestamp. The reason for returning an iterable of accepted events for each
          +state is that when using looping states (e.g. `oneToMany()` and `times()`), more than one events may be accepted for a
          +given state. The selection function returns exactly one result per call.

          {% highlight scala %}

          -def selectFn(pattern : mutable.Map[String, IN]): OUT = {

          • val startEvent = pattern.get("start").get
          • val endEvent = pattern.get("end").get
            +def selectFn(pattern : Map[String, Iterable[IN]]): OUT = { + val startEvent = pattern.get("start").get.next + val endEvent = pattern.get("end").get.next OUT(startEvent, endEvent) } {% endhighlight %}

          -The `flatSelect` method is similar to the `select` method. Their only difference is that the function passed to the `flatSelect` method can return an arbitrary number of results per call.
          -In order to do this, the function for `flatSelect` has an additional `Collector` parameter which is used for the element output.
          +The `flatSelect` method is similar to the `select` method. Their only difference is that the function passed to the
          +`flatSelect` method can return an arbitrary number of results per call. In order to do this, the function for
          +`flatSelect` has an additional `Collector` parameter which is used for forwarding your output elements downstream.
          — End diff –

          ... which is used to forward ...

          Show
          githubbot ASF GitHub Bot added a comment - Github user alpinegizmo commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119886927 — Diff: docs/dev/libs/cep.md — @@ -700,26 +995,29 @@ class MyPatternFlatSelectFunction<IN, OUT> implements PatternFlatSelectFunction< </div> <div data-lang="scala" markdown="1"> -The `select` method takes a selection function as argument, which is called for each matching event sequence. -It receives a map of string/event pairs of the matched events. -The string is defined by the name of the state to which the event has been matched. -The selection function returns exactly one result per call. +The `select()` method takes a selection function as argument, which is called for each matching event sequence. +It receives a match in the form of `Map[String, Iterable [IN] ]` where the key is the name of each state in your pattern +sequence and the value is an Iterable over all accepted events for that state (`IN` is the type of your input elements). +The events for a given state are ordered by timestamp. The reason for returning an iterable of accepted events for each +state is that when using looping states (e.g. `oneToMany()` and `times()`), more than one events may be accepted for a +given state. The selection function returns exactly one result per call. {% highlight scala %} -def selectFn(pattern : mutable.Map [String, IN] ): OUT = { val startEvent = pattern.get("start").get val endEvent = pattern.get("end").get +def selectFn(pattern : Map[String, Iterable [IN] ]): OUT = { + val startEvent = pattern.get("start").get.next + val endEvent = pattern.get("end").get.next OUT(startEvent, endEvent) } {% endhighlight %} -The `flatSelect` method is similar to the `select` method. Their only difference is that the function passed to the `flatSelect` method can return an arbitrary number of results per call. -In order to do this, the function for `flatSelect` has an additional `Collector` parameter which is used for the element output. +The `flatSelect` method is similar to the `select` method. Their only difference is that the function passed to the +`flatSelect` method can return an arbitrary number of results per call. In order to do this, the function for +`flatSelect` has an additional `Collector` parameter which is used for forwarding your output elements downstream. — End diff – ... which is used to forward ...
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user alpinegizmo commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119886720

          — Diff: docs/dev/libs/cep.md —
          @@ -700,26 +995,29 @@ class MyPatternFlatSelectFunction<IN, OUT> implements PatternFlatSelectFunction<
          </div>

          <div data-lang="scala" markdown="1">
          -The `select` method takes a selection function as argument, which is called for each matching event sequence.
          -It receives a map of string/event pairs of the matched events.
          -The string is defined by the name of the state to which the event has been matched.
          -The selection function returns exactly one result per call.
          +The `select()` method takes a selection function as argument, which is called for each matching event sequence.
          +It receives a match in the form of `Map[String, Iterable[IN]]` where the key is the name of each state in your pattern
          +sequence and the value is an Iterable over all accepted events for that state (`IN` is the type of your input elements).
          +The events for a given state are ordered by timestamp. The reason for returning an iterable of accepted events for each
          +state is that when using looping states (e.g. `oneToMany()` and `times()`), more than one events may be accepted for a
          — End diff –

          ... more than one event may be accepted ...

          Show
          githubbot ASF GitHub Bot added a comment - Github user alpinegizmo commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119886720 — Diff: docs/dev/libs/cep.md — @@ -700,26 +995,29 @@ class MyPatternFlatSelectFunction<IN, OUT> implements PatternFlatSelectFunction< </div> <div data-lang="scala" markdown="1"> -The `select` method takes a selection function as argument, which is called for each matching event sequence. -It receives a map of string/event pairs of the matched events. -The string is defined by the name of the state to which the event has been matched. -The selection function returns exactly one result per call. +The `select()` method takes a selection function as argument, which is called for each matching event sequence. +It receives a match in the form of `Map[String, Iterable [IN] ]` where the key is the name of each state in your pattern +sequence and the value is an Iterable over all accepted events for that state (`IN` is the type of your input elements). +The events for a given state are ordered by timestamp. The reason for returning an iterable of accepted events for each +state is that when using looping states (e.g. `oneToMany()` and `times()`), more than one events may be accepted for a — End diff – ... more than one event may be accepted ...
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user alpinegizmo commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119888143

          — Diff: docs/dev/libs/cep.md —
          @@ -341,153 +765,67 @@ Pattern<Event, ?> start = Pattern.<Event>begin("start");
          </td>
          </tr>
          <tr>

          • <td><strong>Next</strong></td>
            + <td><strong>next()</strong></td>
            <td>
          • <p>Appends a new pattern state. A matching event has to directly succeed the previous matching event:</p>
            + <p>Appends a new pattern state. A matching event has to directly succeed the previous matching event
            + (strict contiguity):</p> {% highlight java %}
            -Pattern<Event, ?> next = start.next("next");
            +Pattern<Event, ?> next = start.next("middle");
            {% endhighlight %}
            </td>
            </tr>
            <tr>
            - <td><strong>FollowedBy</strong></td>
            + <td><strong>followedBy()</strong></td>
            <td>
            - <p>Appends a new pattern state. Other events can occur between a matching event and the previous matching event:</p>
            + <p>Appends a new pattern state. Other events can occur between a matching event and the previous
            + matching event (relaxed contiguity):</p>
            {% highlight java %}

            -Pattern<Event, ?> followedBy = start.followedBy("next");
            +Pattern<Event, ?> followedBy = start.followedBy("middle");

            {% endhighlight %}

            </td>
            </tr>
            <tr>

          • <td><strong>Where</strong></td>
            + <td><strong>followedByAny()</strong></td>
            <td>
          • <p>Defines a condition for the current pattern state. Only if an event satisifes the condition, it can match the state:</p>
            + <p>Appends a new pattern state. Other events can occur between a matching event and the previous
            + matching event and alternative matches will be presented for every alternative matching event
              • End diff –

          add a comma:

          ... matching event, and alternative matches ...

          Show
          githubbot ASF GitHub Bot added a comment - Github user alpinegizmo commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119888143 — Diff: docs/dev/libs/cep.md — @@ -341,153 +765,67 @@ Pattern<Event, ?> start = Pattern.<Event>begin("start"); </td> </tr> <tr> <td><strong>Next</strong></td> + <td><strong>next()</strong></td> <td> <p>Appends a new pattern state. A matching event has to directly succeed the previous matching event:</p> + <p>Appends a new pattern state. A matching event has to directly succeed the previous matching event + (strict contiguity):</p> {% highlight java %} -Pattern<Event, ?> next = start.next("next"); +Pattern<Event, ?> next = start.next("middle"); {% endhighlight %} </td> </tr> <tr> - <td><strong>FollowedBy</strong></td> + <td><strong>followedBy()</strong></td> <td> - <p>Appends a new pattern state. Other events can occur between a matching event and the previous matching event:</p> + <p>Appends a new pattern state. Other events can occur between a matching event and the previous + matching event (relaxed contiguity):</p> {% highlight java %} -Pattern<Event, ?> followedBy = start.followedBy("next"); +Pattern<Event, ?> followedBy = start.followedBy("middle"); {% endhighlight %} </td> </tr> <tr> <td><strong>Where</strong></td> + <td><strong>followedByAny()</strong></td> <td> <p>Defines a condition for the current pattern state. Only if an event satisifes the condition, it can match the state:</p> + <p>Appends a new pattern state. Other events can occur between a matching event and the previous + matching event and alternative matches will be presented for every alternative matching event End diff – add a comma: ... matching event, and alternative matches ...
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user alpinegizmo commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119879015

          — Diff: docs/dev/libs/cep.md —
          @@ -168,33 +256,34 @@ start.where(
          </div>
          </div>

          -<span class="label label-danger">Attention</span> The call to `Context.getEventsForPattern(...)` has to find the
          -elements that belong to the pattern. The cost of this operation can vary, so when implementing your condition, try
          -to minimize the times the method is called.
          +<span class="label label-danger">Attention</span> The call to `context.getEventsForPattern(...)` finds all the
          +previously accepted events for a given potential match. The cost of this operation can vary, so when implementing
          +your condition, try to minimize the times the method is called.

          -*Simple Conditions:* This type of conditions extend the aforementioned `IterativeCondition` class. They are simple
          -filtering conditions that decide to accept an element or not, based only on properties of the element itself.
          +*Simple Conditions:* This type of conditions extend the aforementioned `IterativeCondition` class and decides
          — End diff –

          ... This type of condition extends the aforementioned `IterativeCondition` class and decides whether ...

          Show
          githubbot ASF GitHub Bot added a comment - Github user alpinegizmo commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119879015 — Diff: docs/dev/libs/cep.md — @@ -168,33 +256,34 @@ start.where( </div> </div> -<span class="label label-danger">Attention</span> The call to `Context.getEventsForPattern(...)` has to find the -elements that belong to the pattern. The cost of this operation can vary, so when implementing your condition, try -to minimize the times the method is called. +<span class="label label-danger">Attention</span> The call to `context.getEventsForPattern(...)` finds all the +previously accepted events for a given potential match. The cost of this operation can vary, so when implementing +your condition, try to minimize the times the method is called. -* Simple Conditions: * This type of conditions extend the aforementioned `IterativeCondition` class. They are simple -filtering conditions that decide to accept an element or not, based only on properties of the element itself. +* Simple Conditions: * This type of conditions extend the aforementioned `IterativeCondition` class and decides — End diff – ... This type of condition extends the aforementioned `IterativeCondition` class and decides whether ...
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user alpinegizmo commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119888807

          — 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.
          — End diff –

          Now that we have seen what an individual state can look like, ...

          Show
          githubbot ASF GitHub Bot added a comment - Github user alpinegizmo commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119888807 — 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. — End diff – Now that we have seen what an individual state can look like, ...
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user alpinegizmo commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119889674

          — 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>
          — End diff –

          You meant to say "Only if an event is of this subtype, can it match the state:", but I recommend

          ... An event can only match the state if it is of this subtype:

          Show
          githubbot ASF GitHub Bot added a comment - Github user alpinegizmo commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119889674 — 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> — End diff – You meant to say "Only if an event is of this subtype, can it match the state:", but I recommend ... An event can only match the state if it is of this subtype:
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user alpinegizmo commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119890353

          — 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
          — End diff –

          ... can it match the state.

          Or turn the sentence around to be more direct:

          An event matches the state only if it satisfies the condition.

          Show
          githubbot ASF GitHub Bot added a comment - Github user alpinegizmo commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119890353 — 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 — End diff – ... can it match the state. Or turn the sentence around to be more direct: An event matches the state only if it satisfies the condition.
          Hide
          githubbot ASF GitHub Bot added a comment -

          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 ...

          Show
          githubbot ASF GitHub Bot added a comment - 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 ...
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user alpinegizmo commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119891095

          — 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
          — End diff –

          To match the state, an event must satisfy the condition.

          Show
          githubbot ASF GitHub Bot added a comment - Github user alpinegizmo commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119891095 — 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 — End diff – To match the state, an event must satisfy the condition.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user alpinegizmo commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119853002

          — Diff: docs/dev/libs/cep.md —
          @@ -98,48 +128,106 @@ val result: DataStream[Alert] = patternStream.select(createAlert(_))
          </div>
          </div>

          -Note that we use Java 8 lambdas in our Java code examples to make them more succinct.
          -

            1. The Pattern API

          -The pattern API allows you to quickly define complex event patterns.
          -
          -Each pattern consists of multiple stages or what we call states.
          -In order to go from one state to the next, the user can specify conditions.
          -These conditions can be the contiguity of events or a filter condition on an event.
          -
          -Each pattern has to start with an initial state:
          -
          -<div class="codetabs" markdown="1">
          -<div data-lang="java" markdown="1">
          -

          {% highlight java %}
          -Pattern<Event, ?> start = Pattern.<Event>begin("start");
          -{% endhighlight %}
          -</div>
          -
          -<div data-lang="scala" markdown="1">
          -{% highlight scala %}
          -val start : Pattern[Event, _] = Pattern.begin("start")
          -{% endhighlight %}
          -</div>
          -</div>
          -
          -Each state must have a unique name to identify the matched events later on.
          -Additionally, we can specify a filter condition for the event to be accepted as the start event via the `where` method.
          -These filtering conditions can be either an `IterativeCondition` or a `SimpleCondition`.
          -
          -*Iterative Conditions:* This type of conditions can iterate over the previously accepted elements in the pattern and
          -decide to accept a new element or not, based on some statistic over those elements.
          -
          -Below is the code for an iterative condition that accepts elements whose name start with "foo" and for which, the sum
          -of the prices of the previously accepted elements for a state named "middle", plus the price of the current event, do
          -not exceed the value of 5.0. Iterative condition can be very powerful, especially in combination with quantifiers, e.g.
          -`oneToMany` or `zeroToMany`.
          +The pattern API allows you to quickly define complex pattern sequences that you want to extract
          +from your input stream.
          +
          +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for
          +individual events with the same properties. These simple patterns are called *states*. A complex pattern
          +can be seen as a graph of such states, where transition from one state to the next happens based on user-specified
          +conditions, e.g. `event.getName().equals("start")`. A match is a sequence of input events which visit all
          +states of the complex pattern graph, through a sequence of valid state transitions.
          +
          +<span class="label label-danger">Attention</span> Each state must have a unique name to identify the matched
          +events later on.
          +
          +<span class="label label-danger">Attention</span> State names *CANNOT* contain the character `:`.
          +
          +In the remainder, we start by describing how to define [States](#states), before describing how you can
          +combine individual states into [Complex Patterns](#combining-states).
          +
          +### Individual States
          +
          +A *State* can be either a singleton state, or a looping one. Singleton states accept a single
          event, while looping ones can accept more than one. In pattern matching symbols, in the pattern `a b c? d` (or `a`,
          +followed by one or more `b`'s, optionally followed by a `c`, followed by a `d`), `a`, `c?`, and `d` are
          singleton patterns, while `b` is a looping one. By default, a state is a singleton state and you can transform
          +it to a looping one using [Quantifiers](#quantifiers). In addition, each state can have one or more
          +[Conditions](#conditions) based on which it accepts events.
          +
          +#### Quantifiers
          +
          +In FlinkCEP, looping patterns can be specified using the methods: `pattern.oneOrMore()`, for states that expect one or
          more occurrences of a given event (e.g. the `b` mentioned previously), and `pattern.times(#ofTimes)` for states that
          +expect a specific number of occurrences of a given type of event, e.g. 4 `a`'s. All states, looping or not, can be made
          +optional using the `pattern.optional()` method. For a state named `start`, the following are valid quantifiers:
          +
          + <div class="codetabs" markdown="1">
          + <div data-lang="java" markdown="1">
          + {% highlight java %}

          + // expecting 4 occurrences
          + start.times(4);
          +
          + // expecting 0 or 4 occurrences
          + start.times(4).optional();
          +
          + // expecting 1 or more occurrences
          + start.oneOrMore();
          +
          + // expecting 0 or more occurrences
          + start.oneOrMore().optional();
          +

          {% endhighlight %}
          + </div>
          +
          + <div data-lang="scala" markdown="1">
          + {% highlight scala %}
          + // expecting 4 occurrences
          + start.times(4)
          +
          + // expecting 0 or 4 occurrences
          + start.times(4).optional()
          +
          + // expecting 1 or more occurrences
          + start.oneOrMore()
          +
          + // expecting 0 or more occurrences
          + start.oneOrMore().optional()
          + {% endhighlight %}

          + </div>
          + </div>
          +
          +#### Conditions
          +
          +At every state, and in order to go from one state to the next, you can specify additional *conditions*.
          +These conditions can be related to:
          +
          + 1. a [property of the incoming event](#conditions-on-properties), e.g. its value should be larger than 5,
          + or larger than the average value of the previously accepted events.
          +
          + 2. the [contiguity of the matching events](#conditions-on-contiguity), e.g. detect pattern `a,b,c` without
          + non-matching events between any matching ones.
          +
          The latter refers to "looping" states, i.e. states that can accept more than one event, e.g. the `b` in `a b+ c`,
          +which searches for one or more `b`'s.
          +
          +##### Conditions on Properties
          +
          +Conditions on the event properties can be specified via the `pattern.where()` method. These can be either
          +`IterativeCondition`s or `SimpleCondition`s.
          +
          +*Iterative Conditions:* This is the most general type of conditions. This allows to specify a condition that accepts
          +any subsequent event based on some statistic over a subset of the previously accepted events.
          +
          +Below is the code for an iterative condition that accepts the next event for a state named "middle" if its name starts
          +with "foo" and the sum of the prices of the previously accepted events for that state plus the price of the current
          +event, do not exceed the value of 5.0. Iterative conditions can be very powerful, especially in combination with looping
          — End diff –

          The comma doesn't work where it is. I suggest

          Below is the code for an iterative condition that accepts the next event for a state named "middle" if its name starts with "foo", and if the sum of the prices of the previously accepted events for that state plus the price of the current event do not exceed the value of 5.0.

          Show
          githubbot ASF GitHub Bot added a comment - Github user alpinegizmo commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119853002 — Diff: docs/dev/libs/cep.md — @@ -98,48 +128,106 @@ val result: DataStream [Alert] = patternStream.select(createAlert(_)) </div> </div> -Note that we use Java 8 lambdas in our Java code examples to make them more succinct. - The Pattern API -The pattern API allows you to quickly define complex event patterns. - -Each pattern consists of multiple stages or what we call states. -In order to go from one state to the next, the user can specify conditions. -These conditions can be the contiguity of events or a filter condition on an event. - -Each pattern has to start with an initial state: - -<div class="codetabs" markdown="1"> -<div data-lang="java" markdown="1"> - {% highlight java %} -Pattern<Event, ?> start = Pattern.<Event>begin("start"); -{% endhighlight %} -</div> - -<div data-lang="scala" markdown="1"> -{% highlight scala %} -val start : Pattern [Event, _] = Pattern.begin("start") -{% endhighlight %} -</div> -</div> - -Each state must have a unique name to identify the matched events later on. -Additionally, we can specify a filter condition for the event to be accepted as the start event via the `where` method. -These filtering conditions can be either an `IterativeCondition` or a `SimpleCondition`. - -* Iterative Conditions: * This type of conditions can iterate over the previously accepted elements in the pattern and -decide to accept a new element or not, based on some statistic over those elements. - -Below is the code for an iterative condition that accepts elements whose name start with "foo" and for which, the sum -of the prices of the previously accepted elements for a state named "middle", plus the price of the current event, do -not exceed the value of 5.0. Iterative condition can be very powerful, especially in combination with quantifiers, e.g. -`oneToMany` or `zeroToMany`. +The pattern API allows you to quickly define complex pattern sequences that you want to extract +from your input stream. + +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for +individual events with the same properties. These simple patterns are called * states *. A complex pattern +can be seen as a graph of such states, where transition from one state to the next happens based on user-specified + conditions , e.g. `event.getName().equals("start")`. A match is a sequence of input events which visit all +states of the complex pattern graph, through a sequence of valid state transitions. + +<span class="label label-danger">Attention</span> Each state must have a unique name to identify the matched +events later on. + +<span class="label label-danger">Attention</span> State names * CANNOT * contain the character `:`. + +In the remainder, we start by describing how to define [States] (#states), before describing how you can +combine individual states into [Complex Patterns] (#combining-states). + +### Individual States + +A * State * can be either a singleton state, or a looping one. Singleton states accept a single event, while looping ones can accept more than one. In pattern matching symbols, in the pattern `a b c? d` (or `a`, +followed by one or more `b`'s, optionally followed by a `c`, followed by a `d`), `a`, `c?`, and `d` are singleton patterns, while `b ` is a looping one. By default, a state is a singleton state and you can transform +it to a looping one using [Quantifiers] (#quantifiers). In addition, each state can have one or more + [Conditions] (#conditions) based on which it accepts events. + +#### Quantifiers + +In FlinkCEP, looping patterns can be specified using the methods: `pattern.oneOrMore()`, for states that expect one or more occurrences of a given event (e.g. the `b ` mentioned previously), and `pattern.times(#ofTimes)` for states that +expect a specific number of occurrences of a given type of event, e.g. 4 `a`'s. All states, looping or not, can be made +optional using the `pattern.optional()` method. For a state named `start`, the following are valid quantifiers: + + <div class="codetabs" markdown="1"> + <div data-lang="java" markdown="1"> + {% highlight java %} + // expecting 4 occurrences + start.times(4); + + // expecting 0 or 4 occurrences + start.times(4).optional(); + + // expecting 1 or more occurrences + start.oneOrMore(); + + // expecting 0 or more occurrences + start.oneOrMore().optional(); + {% endhighlight %} + </div> + + <div data-lang="scala" markdown="1"> + {% highlight scala %} + // expecting 4 occurrences + start.times(4) + + // expecting 0 or 4 occurrences + start.times(4).optional() + + // expecting 1 or more occurrences + start.oneOrMore() + + // expecting 0 or more occurrences + start.oneOrMore().optional() + {% endhighlight %} + </div> + </div> + +#### Conditions + +At every state, and in order to go from one state to the next, you can specify additional * conditions *. +These conditions can be related to: + + 1. a [property of the incoming event] (#conditions-on-properties), e.g. its value should be larger than 5, + or larger than the average value of the previously accepted events. + + 2. the [contiguity of the matching events] (#conditions-on-contiguity), e.g. detect pattern `a,b,c` without + non-matching events between any matching ones. + The latter refers to "looping" states, i.e. states that can accept more than one event, e.g. the `b ` in `a b+ c`, +which searches for one or more `b`'s. + +##### Conditions on Properties + +Conditions on the event properties can be specified via the `pattern.where()` method. These can be either +`IterativeCondition`s or `SimpleCondition`s. + +* Iterative Conditions: * This is the most general type of conditions. This allows to specify a condition that accepts +any subsequent event based on some statistic over a subset of the previously accepted events. + +Below is the code for an iterative condition that accepts the next event for a state named "middle" if its name starts +with "foo" and the sum of the prices of the previously accepted events for that state plus the price of the current +event, do not exceed the value of 5.0. Iterative conditions can be very powerful, especially in combination with looping — End diff – The comma doesn't work where it is. I suggest Below is the code for an iterative condition that accepts the next event for a state named "middle" if its name starts with "foo", and if the sum of the prices of the previously accepted events for that state plus the price of the current event do not exceed the value of 5.0.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user alpinegizmo commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119887736

          — Diff: docs/dev/libs/cep.md —
          @@ -511,133 +849,81 @@ val start = Pattern.begin[Event]("start")
          </td>
          </tr>
          <tr>

          • <td><strong>Next</strong></td>
            + <td><strong>next()</strong></td>
            <td>
          • <p>Appends a new pattern state. A matching event has to directly succeed the previous matching event:</p>
            + <p>Appends a new pattern state. A matching event has to directly succeed the previous matching event
            + (strict contiguity):</p> {% highlight scala %}
            val next = start.next("middle")
            {% endhighlight %}
            </td>
            </tr>
            <tr>
            - <td><strong>FollowedBy</strong></td>
            + <td><strong>followedBy()</strong></td>
            <td>
            - <p>Appends a new pattern state. Other events can occur between a matching event and the previous matching event:</p>
            + <p>Appends a new pattern state. Other events can occur between a matching event and the previous
            + matching event (relaxed contiguity) :</p>
            {% highlight scala %}

            val followedBy = start.followedBy("middle")

            {% endhighlight %}
            </td>
            </tr>
            <tr>
            - <td><strong>Where</strong></td>
            - <td>
            - <p>Defines a filter condition for the current pattern state. Only if an event passes the filter, it can match the state:</p>
            -{% highlight scala %}
            -patternState.where(event => ... /* some condition */)
            -{% endhighlight %}
          • </td>
          • </tr>
          • <tr>
          • <td><strong>Or</strong></td>
          • <td>
          • <p>Adds a new filter condition which is ORed with an existing filter condition. Only if an event passes the filter condition, it can match the state:</p>
            - {% highlight scala %}

            -patternState.where(event => ... /* some condition */)

          • .or(event => ... /* alternative condition */)
            - {% endhighlight %}
          • </td>
            + <td><strong>followedByAny()</strong></td>
            + <td>
            + <p>Appends a new pattern state. Other events can occur between a matching event and the previous
            + matching event and alternative matches will be presented for every alternative matching event
              • End diff –

          add a comma:

          ... matching event, and alternative matches will be ...

          Show
          githubbot ASF GitHub Bot added a comment - Github user alpinegizmo commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119887736 — Diff: docs/dev/libs/cep.md — @@ -511,133 +849,81 @@ val start = Pattern.begin [Event] ("start") </td> </tr> <tr> <td><strong>Next</strong></td> + <td><strong>next()</strong></td> <td> <p>Appends a new pattern state. A matching event has to directly succeed the previous matching event:</p> + <p>Appends a new pattern state. A matching event has to directly succeed the previous matching event + (strict contiguity):</p> {% highlight scala %} val next = start.next("middle") {% endhighlight %} </td> </tr> <tr> - <td><strong>FollowedBy</strong></td> + <td><strong>followedBy()</strong></td> <td> - <p>Appends a new pattern state. Other events can occur between a matching event and the previous matching event:</p> + <p>Appends a new pattern state. Other events can occur between a matching event and the previous + matching event (relaxed contiguity) :</p> {% highlight scala %} val followedBy = start.followedBy("middle") {% endhighlight %} </td> </tr> <tr> - <td><strong>Where</strong></td> - <td> - <p>Defines a filter condition for the current pattern state. Only if an event passes the filter, it can match the state:</p> -{% highlight scala %} -patternState.where(event => ... /* some condition */) -{% endhighlight %} </td> </tr> <tr> <td><strong>Or</strong></td> <td> <p>Adds a new filter condition which is ORed with an existing filter condition. Only if an event passes the filter condition, it can match the state:</p> - {% highlight scala %} -patternState.where(event => ... /* some condition */) .or(event => ... /* alternative condition */) - {% endhighlight %} </td> + <td><strong>followedByAny()</strong></td> + <td> + <p>Appends a new pattern state. Other events can occur between a matching event and the previous + matching event and alternative matches will be presented for every alternative matching event End diff – add a comma: ... matching event, and alternative matches will be ...
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user alpinegizmo commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119889986

          — 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>
          — End diff –

          An event can only match the state if it passes one of the conditions:

          Show
          githubbot ASF GitHub Bot added a comment - Github user alpinegizmo commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119889986 — 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> — End diff – An event can only match the state if it passes one of the conditions:
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user alpinegizmo commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119852417

          — Diff: docs/dev/libs/cep.md —
          @@ -98,48 +128,105 @@ val result: DataStream[Alert] = patternStream.select(createAlert(_))
          </div>
          </div>

          -Note that we use Java 8 lambdas in our Java code examples to make them more succinct.
          -

            1. The Pattern API

          -The pattern API allows you to quickly define complex event patterns.
          -
          -Each pattern consists of multiple stages or what we call states.
          -In order to go from one state to the next, the user can specify conditions.
          -These conditions can be the contiguity of events or a filter condition on an event.
          -
          -Each pattern has to start with an initial state:
          +The pattern API allows you to quickly define complex pattern sequences that you want to extract
          +from your input stream.
          +
          +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for
          +individual events with the same properties. These simple patterns are called *states*. A complex pattern
          +can be seen as a graph of such states, where transition from one state to the next happens based on user-specified
          +conditions, e.g. `event.getName().equals("start")`. A match is a sequence of input events which visit all
          +states of the complex pattern graph, through a sequence of valid state transitions.
          +
          +<span class="label label-danger">Attention</span> Each state must have a unique name to identify the matched
          +events later on.
          +
          +<span class="label label-danger">Attention</span> State names *CANNOT* contain the character `:`.
          +
          +In the remainder, we start by describing how to define [States](#states), before describing how you can
          +combine individual states into [Complex Patterns](#combining-states).
          +
          +### Individual States
          +
          +A *State* can be either a singleton state, or a looping one. Singleton states accept a single event,
          while looping ones accept more than one. In pattern matching symbols, in the pattern `a b c? d` (or `a`,
          +followed by one or more `b`'s, optionally followed by a `c`, followed by a `d`), `a`, `c?`, and `d` are
          singleton patterns, while `b` is a looping one (see [Quantifiers](#quantifiers)). In addition, each state
          +can have one or more conditions based on which it accepts events (see [Conditions](#conditions)).
          +
          +#### Quantifiers
          +
          +In FlinkCEP, looping patterns can be specified using the methods: `pattern.oneOrMore()`, for states that expect one or
          more occurrences of a given event (e.g. the `b` mentioned previously), and `pattern.times(#ofTimes)` for states that
          +expect a specific number of occurrences of a given type of event, e.g. 4 `a`'s. All states, looping or not, can be made
          +optional using the `pattern.optional()` method. For a state named `start`, the following are valid quantifiers:
          +
          + <div class="codetabs" markdown="1">
          + <div data-lang="java" markdown="1">
          +

          {% highlight java %}

          + // expecting 4 occurrences
          + start.times(4);
          +
          + // expecting 0 or 4 occurrences
          + start.times(4).optional();
          +
          + // expecting 1 or more occurrences
          + start.oneOrMore();
          +
          + // expecting 0 or more occurrences
          + start.oneOrMore().optional();
          +

          {% endhighlight %}
          + </div>
          +
          + <div data-lang="scala" markdown="1">
          + {% highlight scala %}
          + // expecting 4 occurrences
          + start.times(4)
          +
          + // expecting 0 or 4 occurrences
          + start.times(4).optional()
          +
          + // expecting 1 or more occurrences
          + start.oneOrMore()
          +
          + // expecting 0 or more occurrences
          + start.oneOrMore().optional()
          + {% endhighlight %}

          + </div>
          + </div>
          +
          +#### Conditions
          +
          +At every state, and in order to go from one state to the next, you can specify additional *conditions*.
          +These conditions can be related to:
          +
          + 1. a [property of the incoming event](#conditions-on-properties), e.g. its value should be larger than 5,
          + or larger than the average value of the previously accepted events.
          +
          + 2. the [contiguity of the matching events](#conditions-on-contiguity), e.g. detect pattern `a,b,c` without
          + non-matching events between any matching ones.
          +
          The latter refers to "looping" states, i.e. states that can accept more than one event, e.g. the `b` in `a b+ c`,
          +which searches for one or more `b`'s.
          +
          +##### Conditions on Properties
          +
          +Conditions on the event properties can be specified via the `pattern.where()` method. These can be either
          +`IterativeCondition`s or `SimpleCondition`s.
          +
          +*Iterative Conditions:* This is the most general type of conditions. This allows to specify a condition that accepts
          +any subsequent event based on some statistic over a subset of the previously accepted events.
          — End diff –

          This is the most general type of condition. This is how you can specify a condition that accepts subsequent events based on some statistic over a subset of the previously accepted events.

          Show
          githubbot ASF GitHub Bot added a comment - Github user alpinegizmo commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119852417 — Diff: docs/dev/libs/cep.md — @@ -98,48 +128,105 @@ val result: DataStream [Alert] = patternStream.select(createAlert(_)) </div> </div> -Note that we use Java 8 lambdas in our Java code examples to make them more succinct. - The Pattern API -The pattern API allows you to quickly define complex event patterns. - -Each pattern consists of multiple stages or what we call states. -In order to go from one state to the next, the user can specify conditions. -These conditions can be the contiguity of events or a filter condition on an event. - -Each pattern has to start with an initial state: +The pattern API allows you to quickly define complex pattern sequences that you want to extract +from your input stream. + +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for +individual events with the same properties. These simple patterns are called * states *. A complex pattern +can be seen as a graph of such states, where transition from one state to the next happens based on user-specified + conditions , e.g. `event.getName().equals("start")`. A match is a sequence of input events which visit all +states of the complex pattern graph, through a sequence of valid state transitions. + +<span class="label label-danger">Attention</span> Each state must have a unique name to identify the matched +events later on. + +<span class="label label-danger">Attention</span> State names * CANNOT * contain the character `:`. + +In the remainder, we start by describing how to define [States] (#states), before describing how you can +combine individual states into [Complex Patterns] (#combining-states). + +### Individual States + +A * State * can be either a singleton state, or a looping one. Singleton states accept a single event, while looping ones accept more than one. In pattern matching symbols, in the pattern `a b c? d` (or `a`, +followed by one or more `b`'s, optionally followed by a `c`, followed by a `d`), `a`, `c?`, and `d` are singleton patterns, while `b ` is a looping one (see [Quantifiers] (#quantifiers)). In addition, each state +can have one or more conditions based on which it accepts events (see [Conditions] (#conditions)). + +#### Quantifiers + +In FlinkCEP, looping patterns can be specified using the methods: `pattern.oneOrMore()`, for states that expect one or more occurrences of a given event (e.g. the `b ` mentioned previously), and `pattern.times(#ofTimes)` for states that +expect a specific number of occurrences of a given type of event, e.g. 4 `a`'s. All states, looping or not, can be made +optional using the `pattern.optional()` method. For a state named `start`, the following are valid quantifiers: + + <div class="codetabs" markdown="1"> + <div data-lang="java" markdown="1"> + {% highlight java %} + // expecting 4 occurrences + start.times(4); + + // expecting 0 or 4 occurrences + start.times(4).optional(); + + // expecting 1 or more occurrences + start.oneOrMore(); + + // expecting 0 or more occurrences + start.oneOrMore().optional(); + {% endhighlight %} + </div> + + <div data-lang="scala" markdown="1"> + {% highlight scala %} + // expecting 4 occurrences + start.times(4) + + // expecting 0 or 4 occurrences + start.times(4).optional() + + // expecting 1 or more occurrences + start.oneOrMore() + + // expecting 0 or more occurrences + start.oneOrMore().optional() + {% endhighlight %} + </div> + </div> + +#### Conditions + +At every state, and in order to go from one state to the next, you can specify additional * conditions *. +These conditions can be related to: + + 1. a [property of the incoming event] (#conditions-on-properties), e.g. its value should be larger than 5, + or larger than the average value of the previously accepted events. + + 2. the [contiguity of the matching events] (#conditions-on-contiguity), e.g. detect pattern `a,b,c` without + non-matching events between any matching ones. + The latter refers to "looping" states, i.e. states that can accept more than one event, e.g. the `b ` in `a b+ c`, +which searches for one or more `b`'s. + +##### Conditions on Properties + +Conditions on the event properties can be specified via the `pattern.where()` method. These can be either +`IterativeCondition`s or `SimpleCondition`s. + +* Iterative Conditions: * This is the most general type of conditions. This allows to specify a condition that accepts +any subsequent event based on some statistic over a subset of the previously accepted events. — End diff – This is the most general type of condition. This is how you can specify a condition that accepts subsequent events based on some statistic over a subset of the previously accepted events.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user alpinegizmo commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119890712

          — 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>
          — End diff –

          An event can match the state only if it passes at least one of the conditions.

          Show
          githubbot ASF GitHub Bot added a comment - Github user alpinegizmo commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119890712 — 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> — End diff – An event can match the state only if it passes at least one of the conditions.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user alpinegizmo commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r119883989

          — Diff: docs/dev/libs/cep.md —
          @@ -246,63 +333,118 @@ 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 consecutive events:

          -<div class="codetabs" markdown="1">
          -<div data-lang="java" markdown="1">
          -

          {% highlight java %}

          -Pattern<Event, ?> strictNext = start.next("middle");
          -

          {% endhighlight %}
          -</div>
          + 1. Strict Contiguity: which expects all matching events to appear strictly the one after the other,
          + without any non-matching events in-between.

          -<div data-lang="scala" markdown="1">
          -{% highlight scala %}
          -val strictNext: Pattern[Event, _] = start.next("middle")
          -{% endhighlight %}

          -</div>
          -</div>
          + 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.

          -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.
          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`.
          +
          — End diff –

          +1 for the added formatting. I find the explanations hard to parse. How about this:

          1. Strict Contiguity: `

          {a2 b}` – the `"c"` after `"a1"` causes `"a1"` to be discarded.

          2. Relaxed Contiguity: `{a1 b}` and `{a1 a2 b}` – `"c"` is simply ignored.

          3. Non-Deterministic Relaxed Contiguity: `{a1 b}`, `{a2 b}

          `, and `

          {a1 a2 b}

          `.

          Show
          githubbot ASF GitHub Bot added a comment - Github user alpinegizmo commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r119883989 — Diff: docs/dev/libs/cep.md — @@ -246,63 +333,118 @@ 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 consecutive events: -<div class="codetabs" markdown="1"> -<div data-lang="java" markdown="1"> - {% highlight java %} -Pattern<Event, ?> strictNext = start.next("middle"); - {% endhighlight %} -</div> + 1. Strict Contiguity: which expects all matching events to appear strictly the one after the other, + without any non-matching events in-between. -<div data-lang="scala" markdown="1"> -{% highlight scala %} -val strictNext: Pattern [Event, _] = start.next("middle") -{% endhighlight %} -</div> -</div> + 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. -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. 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`. + — End diff – +1 for the added formatting. I find the explanations hard to parse. How about this: 1. Strict Contiguity: ` {a2 b}` – the `"c"` after `"a1"` causes `"a1"` to be discarded. 2. Relaxed Contiguity: `{a1 b}` and `{a1 a2 b}` – `"c"` is simply ignored. 3. Non-Deterministic Relaxed Contiguity: `{a1 b}`, `{a2 b} `, and ` {a1 a2 b} `.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user kl0u commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r120303532

          — Diff: docs/dev/libs/cep.md —
          @@ -98,48 +128,105 @@ val result: DataStream[Alert] = patternStream.select(createAlert(_))
          </div>
          </div>

          -Note that we use Java 8 lambdas in our Java code examples to make them more succinct.
          -

            1. The Pattern API

          -The pattern API allows you to quickly define complex event patterns.
          -
          -Each pattern consists of multiple stages or what we call states.
          -In order to go from one state to the next, the user can specify conditions.
          -These conditions can be the contiguity of events or a filter condition on an event.
          -
          -Each pattern has to start with an initial state:
          +The pattern API allows you to quickly define complex pattern sequences that you want to extract
          +from your input stream.
          +
          +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for
          +individual events with the same properties. These simple patterns are called *states*. A complex pattern
          +can be seen as a graph of such states, where transition from one state to the next happens based on user-specified
          +conditions, e.g. `event.getName().equals("start")`. A match is a sequence of input events which visit all
          +states of the complex pattern graph, through a sequence of valid state transitions.
          +
          +<span class="label label-danger">Attention</span> Each state must have a unique name to identify the matched
          +events later on.
          +
          +<span class="label label-danger">Attention</span> State names *CANNOT* contain the character `:`.
          +
          +In the remainder, we start by describing how to define [States](#states), before describing how you can
          +combine individual states into [Complex Patterns](#combining-states).
          +
          +### Individual States
          +
          +A *State* can be either a singleton state, or a looping one. Singleton states accept a single event,
          while looping ones accept more than one. In pattern matching symbols, in the pattern `a b c? d` (or `a`,
          +followed by one or more `b`'s, optionally followed by a `c`, followed by a `d`), `a`, `c?`, and `d` are
          singleton patterns, while `b` is a looping one (see [Quantifiers](#quantifiers)). In addition, each state
          +can have one or more conditions based on which it accepts events (see [Conditions](#conditions)).
          +
          +#### Quantifiers
          +
          +In FlinkCEP, looping patterns can be specified using the methods: `pattern.oneOrMore()`, for states that expect one or
          more occurrences of a given event (e.g. the `b` mentioned previously), and `pattern.times(#ofTimes)` for states that
          +expect a specific number of occurrences of a given type of event, e.g. 4 `a`'s. All states, looping or not, can be made
          +optional using the `pattern.optional()` method. For a state named `start`, the following are valid quantifiers:
          +
          + <div class="codetabs" markdown="1">
          + <div data-lang="java" markdown="1">
          +

          {% highlight java %}

          + // expecting 4 occurrences
          + start.times(4);
          +
          + // expecting 0 or 4 occurrences
          + start.times(4).optional();
          +
          + // expecting 1 or more occurrences
          + start.oneOrMore();
          +
          + // expecting 0 or more occurrences
          + start.oneOrMore().optional();
          +

          {% endhighlight %}
          + </div>
          +
          + <div data-lang="scala" markdown="1">
          + {% highlight scala %}
          + // expecting 4 occurrences
          + start.times(4)
          +
          + // expecting 0 or 4 occurrences
          + start.times(4).optional()
          +
          + // expecting 1 or more occurrences
          + start.oneOrMore()
          +
          + // expecting 0 or more occurrences
          + start.oneOrMore().optional()
          + {% endhighlight %}

          + </div>
          + </div>
          +
          +#### Conditions
          +
          +At every state, and in order to go from one state to the next, you can specify additional *conditions*.
          +These conditions can be related to:
          +
          + 1. a [property of the incoming event](#conditions-on-properties), e.g. its value should be larger than 5,
          + or larger than the average value of the previously accepted events.
          +
          + 2. the [contiguity of the matching events](#conditions-on-contiguity), e.g. detect pattern `a,b,c` without
          — End diff –

          I agree. The problem is that then we have many back-and-forths. I will try to somehow integrate this comments (probably with a forward reference like "more on contiguity ...").

          Show
          githubbot ASF GitHub Bot added a comment - Github user kl0u commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r120303532 — Diff: docs/dev/libs/cep.md — @@ -98,48 +128,105 @@ val result: DataStream [Alert] = patternStream.select(createAlert(_)) </div> </div> -Note that we use Java 8 lambdas in our Java code examples to make them more succinct. - The Pattern API -The pattern API allows you to quickly define complex event patterns. - -Each pattern consists of multiple stages or what we call states. -In order to go from one state to the next, the user can specify conditions. -These conditions can be the contiguity of events or a filter condition on an event. - -Each pattern has to start with an initial state: +The pattern API allows you to quickly define complex pattern sequences that you want to extract +from your input stream. + +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for +individual events with the same properties. These simple patterns are called * states *. A complex pattern +can be seen as a graph of such states, where transition from one state to the next happens based on user-specified + conditions , e.g. `event.getName().equals("start")`. A match is a sequence of input events which visit all +states of the complex pattern graph, through a sequence of valid state transitions. + +<span class="label label-danger">Attention</span> Each state must have a unique name to identify the matched +events later on. + +<span class="label label-danger">Attention</span> State names * CANNOT * contain the character `:`. + +In the remainder, we start by describing how to define [States] (#states), before describing how you can +combine individual states into [Complex Patterns] (#combining-states). + +### Individual States + +A * State * can be either a singleton state, or a looping one. Singleton states accept a single event, while looping ones accept more than one. In pattern matching symbols, in the pattern `a b c? d` (or `a`, +followed by one or more `b`'s, optionally followed by a `c`, followed by a `d`), `a`, `c?`, and `d` are singleton patterns, while `b ` is a looping one (see [Quantifiers] (#quantifiers)). In addition, each state +can have one or more conditions based on which it accepts events (see [Conditions] (#conditions)). + +#### Quantifiers + +In FlinkCEP, looping patterns can be specified using the methods: `pattern.oneOrMore()`, for states that expect one or more occurrences of a given event (e.g. the `b ` mentioned previously), and `pattern.times(#ofTimes)` for states that +expect a specific number of occurrences of a given type of event, e.g. 4 `a`'s. All states, looping or not, can be made +optional using the `pattern.optional()` method. For a state named `start`, the following are valid quantifiers: + + <div class="codetabs" markdown="1"> + <div data-lang="java" markdown="1"> + {% highlight java %} + // expecting 4 occurrences + start.times(4); + + // expecting 0 or 4 occurrences + start.times(4).optional(); + + // expecting 1 or more occurrences + start.oneOrMore(); + + // expecting 0 or more occurrences + start.oneOrMore().optional(); + {% endhighlight %} + </div> + + <div data-lang="scala" markdown="1"> + {% highlight scala %} + // expecting 4 occurrences + start.times(4) + + // expecting 0 or 4 occurrences + start.times(4).optional() + + // expecting 1 or more occurrences + start.oneOrMore() + + // expecting 0 or more occurrences + start.oneOrMore().optional() + {% endhighlight %} + </div> + </div> + +#### Conditions + +At every state, and in order to go from one state to the next, you can specify additional * conditions *. +These conditions can be related to: + + 1. a [property of the incoming event] (#conditions-on-properties), e.g. its value should be larger than 5, + or larger than the average value of the previously accepted events. + + 2. the [contiguity of the matching events] (#conditions-on-contiguity), e.g. detect pattern `a,b,c` without — End diff – I agree. The problem is that then we have many back-and-forths. I will try to somehow integrate this comments (probably with a forward reference like "more on contiguity ...").
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user kl0u commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r120362519

          — Diff: docs/dev/libs/cep.md —
          @@ -98,48 +128,105 @@ val result: DataStream[Alert] = patternStream.select(createAlert(_))
          </div>
          </div>

          -Note that we use Java 8 lambdas in our Java code examples to make them more succinct.
          -

            1. The Pattern API

          -The pattern API allows you to quickly define complex event patterns.
          -
          -Each pattern consists of multiple stages or what we call states.
          -In order to go from one state to the next, the user can specify conditions.
          -These conditions can be the contiguity of events or a filter condition on an event.
          -
          -Each pattern has to start with an initial state:
          +The pattern API allows you to quickly define complex pattern sequences that you want to extract
          +from your input stream.
          +
          +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for
          +individual events with the same properties. These simple patterns are called *states*. A complex pattern
          — End diff –

          I changed it, so now we have `Pattern` and `Pattern Sequence`.

          Show
          githubbot ASF GitHub Bot added a comment - Github user kl0u commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r120362519 — Diff: docs/dev/libs/cep.md — @@ -98,48 +128,105 @@ val result: DataStream [Alert] = patternStream.select(createAlert(_)) </div> </div> -Note that we use Java 8 lambdas in our Java code examples to make them more succinct. - The Pattern API -The pattern API allows you to quickly define complex event patterns. - -Each pattern consists of multiple stages or what we call states. -In order to go from one state to the next, the user can specify conditions. -These conditions can be the contiguity of events or a filter condition on an event. - -Each pattern has to start with an initial state: +The pattern API allows you to quickly define complex pattern sequences that you want to extract +from your input stream. + +Each such complex pattern sequence consists of multiple simple patterns, i.e. patterns looking for +individual events with the same properties. These simple patterns are called * states *. A complex pattern — End diff – I changed it, so now we have `Pattern` and `Pattern Sequence`.
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user tzulitai commented on a diff in the pull request:

          https://github.com/apache/flink/pull/4041#discussion_r120403427

          — Diff: docs/dev/libs/cep.md —
          @@ -1155,5 +1199,9 @@ The changes required are:
          implementing the `FilterFunction` interface.

          2. Change your functions provided as arguments to the `select(...)` and `flatSelect(...)` methods to expect a list of
          -events associated with each state (`List` in `Java`, `Iterable` in `Scala`). This is because with the addition of
          -the looping states, multiple input events can much a single (looping) state.
          \ No newline at end of file
          +events associated with each pattern (`List` in `Java`, `Iterable` in `Scala`). This is because with the addition of
          +the looping patterns, multiple input events can match a single (looping) pattern.
          +
          +3. The `followedBy()` in Flink 1.1 and 1.2 implied `non-deterministic relaxed contiguity` (see
          — End diff –

          Looks good! 😄

          Show
          githubbot ASF GitHub Bot added a comment - Github user tzulitai commented on a diff in the pull request: https://github.com/apache/flink/pull/4041#discussion_r120403427 — Diff: docs/dev/libs/cep.md — @@ -1155,5 +1199,9 @@ The changes required are: implementing the `FilterFunction` interface. 2. Change your functions provided as arguments to the `select(...)` and `flatSelect(...)` methods to expect a list of -events associated with each state (`List` in `Java`, `Iterable` in `Scala`). This is because with the addition of -the looping states, multiple input events can much a single (looping) state. \ No newline at end of file +events associated with each pattern (`List` in `Java`, `Iterable` in `Scala`). This is because with the addition of +the looping patterns, multiple input events can match a single (looping) pattern. + +3. The `followedBy()` in Flink 1.1 and 1.2 implied `non-deterministic relaxed contiguity` (see — End diff – Looks good! 😄
          Hide
          githubbot ASF GitHub Bot added a comment -

          Github user asfgit closed the pull request at:

          https://github.com/apache/flink/pull/4041

          Show
          githubbot ASF GitHub Bot added a comment - Github user asfgit closed the pull request at: https://github.com/apache/flink/pull/4041
          Hide
          kkl0u Kostas Kloudas added a comment -

          Merged at 6abbba248876379d388bca42f387adde1518f198

          Show
          kkl0u Kostas Kloudas added a comment - Merged at 6abbba248876379d388bca42f387adde1518f198

            People

            • Assignee:
              kkl0u Kostas Kloudas
              Reporter:
              kkl0u Kostas Kloudas
            • Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development