Overview of query application components
While queries can make up the central logic of an Apama deployment, deploying an Apama query application also requires event definitions, and connections to event sinks and event sources. Optionally, an Apama query application can make use of EPL plug-ins, EPL actions, and interactions with EPL monitors.
In addition to queries, the following components are required to implement a query application.
Event definitions. This includes event types used by adapters or mapped from message busses (see below) or used internally within application components. Typically, event types specific to an adapter or to existing messages on a message bus would be written by those creating or configuring the adapter.
Connections between event sources and queries and also between queries and event sinks. This is typically handled by adapters or by mapping to messages on a message bus by means of JMS. For testing, it is possible to use
Software AG Designer or command line tools to send and receive messages.
A correlator process. Several queries can share the same correlator process. Queries can be started by Ant scripts, which can be exported from an Apama project. For testing,
Software AG Designer can start the queries.
Optionally, queries can use a library of functions that you provide. These would be written in EPL and can call EPL plug-ins written in C++ or Java. Functions in such a library can be invoked from different points in a query.
For additional information, see
Query application architecture .
Writing event definitions
Event definitions are defined in Apama .mon files. When writing event type definitions be sure to consider the following:
An
inputs block in a query can specify filters on event fields of type
boolean,
decimal,
float,
integer,
string or
location.
An event field to be specified as a query key must be of type
boolean,
decimal,
float,
integer,
string or
location.
An event field to be specified in an
inputs block, whether as a filter or a key, cannot be marked with the
wildcard modifier in the event type definition.
A
where condition in a query can make use of all actions and fields of events, including members of reference types such as
sequence,
dictionary and other events.
Specifying an event filter in an
inputs block is very efficient because it prevents any part of the query from executing if the filter condition does not match. However, a filter in an
inputs block can operate on only contiguous ranges and can compare only a single field to a constant or parameter value.
Specifying an event filter in a where condition is more expensive than specifying an event filter in an inputs block. However, a filter in a where clause can be more powerful because it can specify any EPL expression.
A query cannot use an event that contains an
action variable or fields of type
chunk or
listener.
If you want to take advantage of the source timestamp functionality, be sure to add an event field that records the time of the creation of the data encapsulated in the event, and an action that returns this time in the form of a float representing the number of seconds since the epoch (midnight , 1 Jan 1970 UTC). If the time data is not in this format, you can use the TimeFormat event library to perform the relevant conversions (for further information, see
Using the TimeFormat event library).
For example, consider the following event definitions:
event Slice {
integer quantity;
float price;
}
event UsableEvent {
integer quantity;
string username;
wildcard string auxData;
sequence<Slice> slices;
action averagePrice() returns float {
float t:=0;
Slice s;
for s in slices {
t:=t+s.price;
}
return t/(slices.length().toFloat());
}
}
event InternalEvent {
action<> returns float averager;
}
UsableEvent.quantity and UsableEvent.username can be used in a query inputs block or in a query where condition.
UsableEvent.auxData, UsableEvent.slices and UsableEvent.averagePrice() can be used in where conditions but not in inputs blocks.
InternalEvent cannot be an input to a query because it has an action variable. However, an instance of InternalEvent could be used in a where condition or in triggered EPL code in a find block.
For example, the find statement in a query can be written as follows:
find UsableEvent as e1 and UsableEvent as e2
where e1.averagePrice() > e2.averagePrice()
and
e1.slices[0].price < e2.slices[0].price
Action definitions can supply helper actions such as the averagePrice() action above. This can be useful in both event types used by adapters and in internal event types. For example, some event types may have no members but simply be a named container for useful library actions.
To make use of EPL plug-ins written in C, C++ or Java, it is recommended to write an EPL event type or set of event types that wrap the plug-in. This provides a more consistent interface and can add type safety to the use of chunks, which are opaquely-typed C, C++ or Java objects. These EPL actions can then be called from queries, as can any EPL action.
Event sinks and sources
A typical deployment includes adapters that connect the Apama system to external sources of data or provide the means to send events out of Apama. This can include:
For testing purposes, Software AG Designer can send / receive events from / to files, and command line tools are provided as well.
Correlator process
When developing queries in Software AG Designer, launching a configuration starts a correlator and injects queries into it by default. It is also possible to export the Apama launch configuration to an Ant script, which can be copied onto another machine such as a server to run your project on that machine.
It is possible to run multiple correlators that are configured to use the same distributed cache store. These correlators share query state. In such deployments, the recommendation is to use a JMS message queue. Typically, these deployments would use correlators on separate physical machines so a failure of one does not affect others. For testing, it is possible to run several correlators on a single machine provided a separate port number is allocated to each correlator. Take care to use the correct port number when interacting with the correlators.