Apama 10.7.2 | Introduction to Apama | Apama Architecture | Descriptions of Apama components | Description of event processing languages | Introduction to Apama EPL
 
Introduction to Apama EPL
Before EPL can look for patterns in event streams, you must define the types of events you are interested in and inject their definitions in the correlator. An event definition informs the correlator about the composition of an event type. An example event definition for a stock exchange tick feed is as follows:
event StockTick {
   string symbol;
   float price;
   float volume;
}
Each field of the event has a type and a name. The type informs the correlator how to handle that field and what operations to allow on it. As you can see, the correlator can handle multiple types, such as numeric values and textual values, within the same event type. Apama can handle any number of different event types at one time.
External event sources such as connectivity plug-ins, clients and the IAF need to be able to send events into the correlator. For the correlator to be able to detect an event of interest, the event's type definition must have been loaded into the correlator. An example of a StockTick event is as follows:
StockTick ("APAMA", 55.20, 250010)
There are two basic EPL structures called monitors and queries.
Apama monitors
A monitor defines:
*One or more listeners. EPL provides event listeners and stream listeners.
*An event listener observes the correlator event stream analyzing each event in turn until it finds a sequence of events that match its event expression. When this happens the event listener triggers, causing the correlator to execute the listener action.
*A stream listener passes stream query output to procedural code. A stream query operates on one or two streams to transform their contents into a single output stream. The type of the stream query output items need not be the same as the type of the stream query input items. The output for one stream query can be the input for another stream query. At the end of the chain of stream queries, a stream listener coassigns each stream query output item to a variable and executes specified code.
*One or more actions. An action is one or more operations that the correlator performs. An action might be to register a listener or it might be an operation to perform when the correlator finds a match between an incoming event or sequence and a listener.
The following EPL example illustrates these concepts in the form of a simple monitor called PriceRise. The monitor is composed of three actions. The first two actions declare listeners, which are indicated by the on keyword.
monitor PriceRise
{   
action onload() {
      on all StockTick("IBM",>=75.5,*) as firstTick {
         furtherRise (firstTick);
      }
      from tick in all StockTick(symbol="IBM")
         within 60.0 every 60.0
         select mean(tick.price) as f { average(tick.price); }
   }
   action average(float av) {
      log "60-second average for IBM: "+av.toString();
   }
   action furtherRise(StockTick tick) {
      on all StockTick("IBM",>=(tick.price*1.05),*) as finalTick {
         log "IBM has hit "+finalTick.price.toString();
         emit PlaceSellOrder("IBM",finalTick.price,1000.0);
      }
   }
}
When a monitor starts running, the correlator executes the monitor's onload() action. In the PriceRise monitor, the onload() action creates an event listener for all IBM stock ticks that have a price above 75.5 at any volume and a stream listener for all IBM stock ticks. Since the last field of the event (volume) is irrelevant to the event listener it is represented by an asterisk (*), which indicates a wildcard. This monitor effectively goes to sleep until the correlator detects an IBM stock tick.
If the correlator detects an IBM stock tick, the stream listener takes it as input and uses it to log 60-second averages for IBM stock prices. If the IBM stock tick also has a price that is greater than or equal to 75.5, the correlator copies the field values in that event to the firstTick variable and calls the furtherRise() action.
The furtherRise() action creates another event listener. This event listener is looking for the next part of the event pattern, which involves detecting if the IBM stock price goes up by more than 5% from its new value. The second listener uses the firstTick variable to obtain the price value in the event that caused the first listener to detect a match. If the price rise occurs, the correlator copies the values in the matching, incoming event to the finalTick variable, and executes the associated block of code.
The associated block of code logs the new price and emits a PlaceSellOrder event to a receiver that is external to the correlator. For example, an adapter can pick up this event, and translate it into a message that an order book can operate on. The PlaceSellOrder event causes placement of an order for 1000 units of IBM stock.
Apama queries
An Apama query does the following:
*Operates on only specified input events. You can specify one or more event types. For each event type, you can filter event content so that the query operates on only certain instances of that event.
*Partitions input events according to their keys — Based on the values of selected fields in incoming events, the correlator segregates events into many separate partitions. Partitions typically relate to real-world entities that you are monitoring such as bank accounts, cell phones, or subscriptions. For example, an automated bank machine associates an account number with every transaction. You can define a query that partitions Withdrawal events based on their account number. Each partition could contain the Withdrawal events for one account. This lets you look for withdrawal patterns that look suspicious.
Typically, a query application operates on a huge number of partitions with a relatively small number of events in each partition. Each partition is identified by a unique key value, such as an account number.
*Watches for the event pattern of interest across all partitions. An event pattern can define a sequence of events as well as conditions that determine whether there is a match. A condition can be a filter that specifies a Boolean expression that must evaluate to true for there to be a match, a time constraint that requires some or all elements in the pattern to occur within a given time period, or an exclusion, which is an event whose presence prevents a match.
*Executes specified actions when a pattern match is found. Actions can send events. This is how a query can communicate with other queries, with monitor instances, and with external system elements in a deployment, such as adapters, correlators, or other deployed processes.
*Optionally uses parameters. When a query has no parameters, a single instance of the query is automatically created when the query is loaded into a correlator. If one or more parameters are defined for a query then when the query is loaded into a correlator, no instances are created until you specify parameter values.
The following simple query example illustrates these concepts:
query ImprobableWithdrawalLocations {
parameters {
float period;
}
inputs {
Withdrawal(value>500) key cardNumber within period;
}
find Withdrawal as w1 -> Withdrawal as w2
where w2.country != w1.country {
log "Suspicious withdrawal: " + w2.toString() at INFO;
}
}
The optional parameters block in a query definition specifies parameters for which you must supply values so that an instance of the query (a parameterization) can be created. A query that defines parameters functions as a template for multiple parameterizations. Each parameterization of the simple query above would watch for the identified Withdrawal events for a different time period.
The inputs block of a query definition identifies the events that the query operates on. The example query operates only those Withdrawal events whose value field is greater than 500 and that arrived within the time range specified by the value of the period parameter. You can also specify that no more than a particular number of events can be in each partition at a given moment.
In the example, the Withdrawal input definition specifies the cardNumber field as the key. The query partitions incoming Withdrawal events according to their card numbers.
The find statement specifies the pattern you are looking for. In the example, the pattern of interest is a Withdrawal event followed by another Withdrawal event where the country fields for the two events are different. Since a query operates on the events in each partition independently of the other partitions, this pattern suggests a suspicious transaction.
Finally, when a query finds a match it executes the statements in its find block. In the example, the query logs a message that contains the Withdrawal event that triggered the match.
See also Understanding queries and Architectural comparison of queries and monitors.