You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@flink.apache.org by "Ivan Mushketyk (JIRA)" <ji...@apache.org> on 2016/08/23 20:34:22 UTC
[jira] [Comment Edited] (FLINK-3414) Add Scala API for CEP's
pattern definition
[ https://issues.apache.org/jira/browse/FLINK-3414?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15404852#comment-15404852 ]
Ivan Mushketyk edited comment on FLINK-3414 at 8/23/16 8:34 PM:
----------------------------------------------------------------
I would like to describe my proposal on the case-by-case basis. Feel free to point on any gaps and inconsistencies in this design.
Also, I am not sure what is the best medium for this kind of discussion. I will start it here, but if you find it inconvenient or sub-optimal, I can move it to some other place.
Let's start with a simplest pattern that expects a single event:
{code:java}
Pattern.begin("start").where(evt -> evt.getId() == 42)
{code}
This can be replaced with a much shorter Scala version
{code:java}
pattern "start" _.getId() == 42
{code}
A single function call *pattern* can replace *Pattern.begin* call and *where* condition can be added as an argument to this function call.
A pattern that is expecting a specific type like this one:
{code:java}
Pattern.begin("start").where(evt -> evt.getId() == 42)
.subtype(SubEvent.class)
{code}
Can be replaced with the following Scala code:
{code:java}
pattern[SubEvent] "start" _.id == 42
{code}
The type of an object that is expected can be added as a type parameter to the "pattern" function.
The *next* function can be replaced with the *->* operator:
{code:java}
Pattern.begin("start").where(evt -> evt.getId() == 42)
.subtype(SubEvent.class)
.next("next").where(evt -> evt.getId() > 42)
.subtype(SubEvent.class)
{code}
as in this code snippet:
{code:java}
pattern[SubEvent] "start" _.id == 42 ->[SubEvent] _.getId() > 42
{code}
or with a function call:
{code:java}
pattern[SubEvent] "start" _.id == 42 next[SubEvent] _.getId() > 42
{code}
A followedBy can be replaced with a *->>* operator:
{code:java}
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"));
{code}
as in the following example:
{code:java}
pattern "start" _.getId() == 42
->[SubEvent] "middle" _.getVolume() >= 10.0
->> "end" _.getName() == "end"
{code}
A *within* function call can be replaced with *in* function that expects an instance of a FinateDuration class that can provide a more readable code:
{code:java}
pattern "start" -> "middle" _.getName() == "error" ->> "end" _.getName() == "critical" in 10 seconds
{code}
h3. Additional operators
As far as I understand *or* and *not* operators are not yet implemented, but here are few examples for these operators
{code:java}
// Pattern that has an event that is not SubEvent
pattern "start" ! is[SubEvent]
{code}
This example also shows an alternative way of specifying a type of element with the *is* function.
{code:java}
// Pattern that has type SubEvent or has id 42
pattern "start" is[SubEvent] || is _.getId() == 42
{code}
h3. Quantifiers
Quantifiers for patterns are currently in PR, but here how they could be implemented.
{code:java}
pattern "start" is[SubEvent] * // zero or many
pattern "start" is[SubEvent] + // one or many
pattern "start" is[SubEvent] ? // optional
{code}
To mark that a pattern should be repeated specific number of time I suggest to introduce a method "rep" that can be used like this:
{code:java}
pattern "start" is[SubEvent] rep(5) // repeat 5 times
pattern "start" is[SubEvent] rep(3, 10) // repeat from 3 to 10 times inclusive
{code}
was (Author: ivan.mushketyk):
I would like to describe my proposal on the case-by-case basis. Feel free to point on any gaps and inconsistencies in this design.
Also, I am not sure what is the best medium for this kind of discussion. I will start it here, but if you find it inconvenient or sub-optimal, I can move it to some other place.
Let's start with a simplest pattern that expects a single event:
{code:java}
Pattern.begin("start").where(evt -> evt.getId() == 42)
{code}
This can be replaced with a much shorter Scala version
{code:java}
pattern "start" _.getId() == 42
{code}
A single function call *pattern* can replace *Pattern.begin* call and *where* condition can be added as an argument to this function call.
A pattern that is expecting a specific type like this one:
{code:java}
Pattern.begin("start").where(evt -> evt.getId() == 42)
.subtype(SubEvent.class)
{code}
Can be replaced with the following Scala code:
{code:java}
pattern[SubEvent] "start" _.id == 42
{code}
The type of an object that is expected can be added as a type parameter to the "pattern" function.
The *next* function can be replaced with the *->* operator:
{code:java}
Pattern.begin("start").where(evt -> evt.getId() == 42)
.subtype(SubEvent.class)
.next("next").where(evt -> evt.getId() > 42)
.subtype(SubEvent.class)
{code}
as in this code snippet:
{code:java}
pattern[SubEvent] "start" _.id == 42 ->[SubEvent] _.getId() > 42
{code}
or with a function call:
{code:java}
pattern[SubEvent] "start" _.id == 42 next[SubEvent] _.getId() > 42
{code}
A followedBy can be replaced with a *->>* operator:
{code:java}
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"));
{code}
as in the following example:
{code:java}
pattern "start" _.getId() == 42
->[SubEvent] "middle" _.getVolume() >= 10.0
->> "end" _.getName() == "end"
{code}
A *within* function call can be replaced with *in* function that expects an instance of a FinateDuration class that can provide a more readable code:
{code:java}
pattern "start" -> "middle" _.getName() == "error" ->> "end" _.getName() == "critical" in 10 seconds
{code}
h3. Additional operators
As far as I understand *or* and *not* operators are not yet implemented, but here are few examples for these operators
{code:java}
// Pattern that has an event that is not SubEvent
pattern "start" ! is[SubEvent]
{code}
This example also shows an alternative way of specifying a type of element with the *is* function.
{code:java}
// Pattern that has type SubEvent or has id 42
pattern "start" is[SubEvent] || is _.getId() == 42
{code}
> Add Scala API for CEP's pattern definition
> ------------------------------------------
>
> Key: FLINK-3414
> URL: https://issues.apache.org/jira/browse/FLINK-3414
> Project: Flink
> Issue Type: Improvement
> Components: CEP
> Affects Versions: 1.0.0
> Reporter: Till Rohrmann
> Assignee: Ivan Mushketyk
> Priority: Minor
>
> Currently, the CEP library only supports a Java API to specify complex event patterns. In order to make it a bit less verbose for Scala users, it would be nice to also add a Scala API for the CEP library.
> A Scala API would also allow to pass Scala's anonymous functions as filter conditions or as a select function, for example, or to use partial functions to distinguish between different events.
> Furthermore, the Scala API could be designed to feel a bit more like a DSL:
> {code}
> begin "start" where _.id >= 42 -> "middle_1" as classOf[Subclass] || "middle_2" where _.name equals "foobar" -> "end" where x => x.id <= x.volume
> {code}
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)