Continuous Queries
The C++ and .NET Framework clients can initiate queries that run on the Geode cache server and notify the client when the query results have changed. For details on the server-side setup for continuous queries, see How Continuous Querying Works in the Geode User Guide.
Continuous Query Basics
Continuous querying provides the following features:
Standard Geode native client query syntax and semantics. Continuous queries are expressed in the same language used for other native client queries. See Remote Queries.
Standard Geode events-based management of CQ events. The event handling used to process CQ events is based on the standard Geode event handling framework.
Complete integration with the client/server architecture. CQ functionality uses existing server-to-client messaging mechanisms to send events. All tuning of your server-to-client messaging also tunes the messaging of your CQ events. If your system is configured for high availability then your CQs are highly available, with seamless failover provided in case of server failure (see Highly Available Client/Server Event Messaging). If your clients are durable, you can also define any of your CQs as durable (see Implementing Durable Client/Server Messaging).
Interest criteria based on data values. Continuous queries are run against the region’s entry values. Compare this to register interest by reviewing Registering Interest for Entries.
Active query execution. Once initialized, the queries operate on new events. Events that change the query result are sent to the client immediately.
Note: Because floating point numbers can not reliably be compared for equality, do not use floating point values as keys or key components when constructing a query.
Typical Continuous Query Lifecycle
- The client creates the CQ. This sets up everything for running the query and provides the client with a
CqQuery
object, but does not execute the CQ. At this point, the query is in aSTOPPED
state, ready to be closed or run. The client initiates the CQ with an API call to one of the
CqQuery execute*
methods. This puts the query into aRUNNING
state on the client and on the server. The server remotely evaluates the query string, and optionally returns the results to the client.CqQuery execute*
methods include:CqQuery.execute()
CqQuery.executeWithInitialResults()
A CQ Listener waits for events. When it receives events, it takes action accordingly with the data in the CqEvent.
The CQ is closed by a client call to
CqQuery.close
. This de-allocates all resources in use for the CQ on the client and server. At this point, the cycle could begin again with the creation of a newCqQuery
instance.
Executing a Continuous Query from the Client
The essential steps to create and execute a continuous query are:
- Create an instance of the
QueryService
class. If you are using the pool API (recommended), you should obtain theQueryService
from the pool. - Define a CQ Listener (a
CqListener
) to field events sent from the server. - Use one of the
CqQuery execute*
methods to submit the query string to the cache server. - The server remotely evaluates the query string, then monitors those results and notifies the client if they change.
- The client listens for changes that match the query predicate.
- Iterate through the returned objects.
- When finished, close down the continuous query.
C++ Continuous Query Example
These C++ code excerpts are from the examples/cpp/continuousquery
example included in your client
distribution. See the example for full context.
Following the steps listed above,
Create a query service:
auto queryService = pool->getQueryService();
Define a CqListener:
class MyCqListener : public CqListener {
Create an instance of your CqListener and insert it into a CQ attributes object:
CqAttributesFactory cqFactory; auto cqListener = std::make_shared<MyCqListener>(); cqFactory.addCqListener(cqListener); auto cqAttributes = cqFactory.create();
Create a Continuous Query using the query service and the CQ attributes:
auto query = queryService->newCq( "MyCq", "SELECT * FROM /custom_orders c WHERE c.quantity > 30", cqAttributes);
Execute the query:
query->execute();
Wait for events and do something with them.
/* Excerpt from the CqListener */ /* Determine Operation Type */ switch (cqEvent.getQueryOperation()) { case CqOperation::OP_TYPE_CREATE: opStr = "CREATE"; break; case CqOperation::OP_TYPE_UPDATE: opStr = "UPDATE"; break; case CqOperation::OP_TYPE_DESTROY: opStr = "DESTROY"; break; default: break; } ... /* Take action based on OP Type */
When finished, close up shop.
query->execute(); ... (respond to events as they arrive) query->stop(); query->close(); cache.close();